├── .env ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── README.md ├── public └── default.png └── src ├── authenticate_token.rs ├── config.rs ├── github_oauth.rs ├── google_oauth.rs ├── handler.rs ├── main.rs ├── model.rs └── response.rs /.env: -------------------------------------------------------------------------------- 1 | CLIENT_ORIGIN=http://localhost:3000 2 | 3 | JWT_SECRET=my_ultra_secure_secret 4 | TOKEN_EXPIRED_IN=60m 5 | TOKEN_MAXAGE=60 6 | 7 | GOOGLE_OAUTH_CLIENT_ID= 8 | GOOGLE_OAUTH_CLIENT_SECRET= 9 | GOOGLE_OAUTH_REDIRECT_URL=http://localhost:8000/api/sessions/oauth/google 10 | 11 | GITHUB_OAUTH_CLIENT_ID= 12 | GITHUB_OAUTH_CLIENT_SECRET= 13 | GITHUB_OAUTH_REDIRECT_URL=http://localhost:8000/api/sessions/oauth/github -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /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", 20 | ] 21 | 22 | [[package]] 23 | name = "actix-cors" 24 | version = "0.6.4" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" 27 | dependencies = [ 28 | "actix-utils", 29 | "actix-web", 30 | "derive_more", 31 | "futures-util", 32 | "log", 33 | "once_cell", 34 | "smallvec", 35 | ] 36 | 37 | [[package]] 38 | name = "actix-files" 39 | version = "0.6.2" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" 42 | dependencies = [ 43 | "actix-http", 44 | "actix-service", 45 | "actix-utils", 46 | "actix-web", 47 | "askama_escape", 48 | "bitflags", 49 | "bytes", 50 | "derive_more", 51 | "futures-core", 52 | "http-range", 53 | "log", 54 | "mime", 55 | "mime_guess", 56 | "percent-encoding", 57 | "pin-project-lite", 58 | ] 59 | 60 | [[package]] 61 | name = "actix-http" 62 | version = "3.2.2" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724" 65 | dependencies = [ 66 | "actix-codec", 67 | "actix-rt", 68 | "actix-service", 69 | "actix-utils", 70 | "ahash", 71 | "base64 0.13.1", 72 | "bitflags", 73 | "brotli", 74 | "bytes", 75 | "bytestring", 76 | "derive_more", 77 | "encoding_rs", 78 | "flate2", 79 | "futures-core", 80 | "h2", 81 | "http", 82 | "httparse", 83 | "httpdate", 84 | "itoa", 85 | "language-tags", 86 | "local-channel", 87 | "mime", 88 | "percent-encoding", 89 | "pin-project-lite", 90 | "rand", 91 | "sha1", 92 | "smallvec", 93 | "tracing", 94 | "zstd", 95 | ] 96 | 97 | [[package]] 98 | name = "actix-macros" 99 | version = "0.2.3" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" 102 | dependencies = [ 103 | "quote", 104 | "syn", 105 | ] 106 | 107 | [[package]] 108 | name = "actix-router" 109 | version = "0.5.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" 112 | dependencies = [ 113 | "bytestring", 114 | "http", 115 | "regex", 116 | "serde", 117 | "tracing", 118 | ] 119 | 120 | [[package]] 121 | name = "actix-rt" 122 | version = "2.7.0" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" 125 | dependencies = [ 126 | "futures-core", 127 | "tokio", 128 | ] 129 | 130 | [[package]] 131 | name = "actix-server" 132 | version = "2.1.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" 135 | dependencies = [ 136 | "actix-rt", 137 | "actix-service", 138 | "actix-utils", 139 | "futures-core", 140 | "futures-util", 141 | "mio", 142 | "num_cpus", 143 | "socket2", 144 | "tokio", 145 | "tracing", 146 | ] 147 | 148 | [[package]] 149 | name = "actix-service" 150 | version = "2.0.2" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" 153 | dependencies = [ 154 | "futures-core", 155 | "paste", 156 | "pin-project-lite", 157 | ] 158 | 159 | [[package]] 160 | name = "actix-utils" 161 | version = "3.0.1" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" 164 | dependencies = [ 165 | "local-waker", 166 | "pin-project-lite", 167 | ] 168 | 169 | [[package]] 170 | name = "actix-web" 171 | version = "4.2.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9" 174 | dependencies = [ 175 | "actix-codec", 176 | "actix-http", 177 | "actix-macros", 178 | "actix-router", 179 | "actix-rt", 180 | "actix-server", 181 | "actix-service", 182 | "actix-utils", 183 | "actix-web-codegen", 184 | "ahash", 185 | "bytes", 186 | "bytestring", 187 | "cfg-if", 188 | "cookie", 189 | "derive_more", 190 | "encoding_rs", 191 | "futures-core", 192 | "futures-util", 193 | "http", 194 | "itoa", 195 | "language-tags", 196 | "log", 197 | "mime", 198 | "once_cell", 199 | "pin-project-lite", 200 | "regex", 201 | "serde", 202 | "serde_json", 203 | "serde_urlencoded", 204 | "smallvec", 205 | "socket2", 206 | "time 0.3.17", 207 | "url", 208 | ] 209 | 210 | [[package]] 211 | name = "actix-web-codegen" 212 | version = "4.1.0" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "1fa9362663c8643d67b2d5eafba49e4cb2c8a053a29ed00a0bea121f17c76b13" 215 | dependencies = [ 216 | "actix-router", 217 | "proc-macro2", 218 | "quote", 219 | "syn", 220 | ] 221 | 222 | [[package]] 223 | name = "adler" 224 | version = "1.0.2" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 227 | 228 | [[package]] 229 | name = "ahash" 230 | version = "0.7.6" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 233 | dependencies = [ 234 | "getrandom", 235 | "once_cell", 236 | "version_check", 237 | ] 238 | 239 | [[package]] 240 | name = "aho-corasick" 241 | version = "0.7.20" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" 244 | dependencies = [ 245 | "memchr", 246 | ] 247 | 248 | [[package]] 249 | name = "alloc-no-stdlib" 250 | version = "2.0.4" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" 253 | 254 | [[package]] 255 | name = "alloc-stdlib" 256 | version = "0.2.2" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" 259 | dependencies = [ 260 | "alloc-no-stdlib", 261 | ] 262 | 263 | [[package]] 264 | name = "android_system_properties" 265 | version = "0.1.5" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 268 | dependencies = [ 269 | "libc", 270 | ] 271 | 272 | [[package]] 273 | name = "askama_escape" 274 | version = "0.10.3" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" 277 | 278 | [[package]] 279 | name = "autocfg" 280 | version = "1.1.0" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 283 | 284 | [[package]] 285 | name = "base64" 286 | version = "0.13.1" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 289 | 290 | [[package]] 291 | name = "base64" 292 | version = "0.21.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" 295 | 296 | [[package]] 297 | name = "bitflags" 298 | version = "1.3.2" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 301 | 302 | [[package]] 303 | name = "block-buffer" 304 | version = "0.10.3" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" 307 | dependencies = [ 308 | "generic-array", 309 | ] 310 | 311 | [[package]] 312 | name = "brotli" 313 | version = "3.3.4" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" 316 | dependencies = [ 317 | "alloc-no-stdlib", 318 | "alloc-stdlib", 319 | "brotli-decompressor", 320 | ] 321 | 322 | [[package]] 323 | name = "brotli-decompressor" 324 | version = "2.3.4" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" 327 | dependencies = [ 328 | "alloc-no-stdlib", 329 | "alloc-stdlib", 330 | ] 331 | 332 | [[package]] 333 | name = "bumpalo" 334 | version = "3.12.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 337 | 338 | [[package]] 339 | name = "bytes" 340 | version = "1.3.0" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" 343 | 344 | [[package]] 345 | name = "bytestring" 346 | version = "1.2.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "f7f83e57d9154148e355404702e2694463241880b939570d7c97c014da7a69a1" 349 | dependencies = [ 350 | "bytes", 351 | ] 352 | 353 | [[package]] 354 | name = "cc" 355 | version = "1.0.78" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" 358 | dependencies = [ 359 | "jobserver", 360 | ] 361 | 362 | [[package]] 363 | name = "cfg-if" 364 | version = "1.0.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 367 | 368 | [[package]] 369 | name = "chrono" 370 | version = "0.4.23" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" 373 | dependencies = [ 374 | "iana-time-zone", 375 | "js-sys", 376 | "num-integer", 377 | "num-traits", 378 | "serde", 379 | "time 0.1.45", 380 | "wasm-bindgen", 381 | "winapi", 382 | ] 383 | 384 | [[package]] 385 | name = "codespan-reporting" 386 | version = "0.11.1" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" 389 | dependencies = [ 390 | "termcolor", 391 | "unicode-width", 392 | ] 393 | 394 | [[package]] 395 | name = "convert_case" 396 | version = "0.4.0" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 399 | 400 | [[package]] 401 | name = "cookie" 402 | version = "0.16.2" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" 405 | dependencies = [ 406 | "percent-encoding", 407 | "time 0.3.17", 408 | "version_check", 409 | ] 410 | 411 | [[package]] 412 | name = "core-foundation" 413 | version = "0.9.3" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 416 | dependencies = [ 417 | "core-foundation-sys", 418 | "libc", 419 | ] 420 | 421 | [[package]] 422 | name = "core-foundation-sys" 423 | version = "0.8.3" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 426 | 427 | [[package]] 428 | name = "cpufeatures" 429 | version = "0.2.5" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" 432 | dependencies = [ 433 | "libc", 434 | ] 435 | 436 | [[package]] 437 | name = "crc32fast" 438 | version = "1.3.2" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 441 | dependencies = [ 442 | "cfg-if", 443 | ] 444 | 445 | [[package]] 446 | name = "crypto-common" 447 | version = "0.1.6" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 450 | dependencies = [ 451 | "generic-array", 452 | "typenum", 453 | ] 454 | 455 | [[package]] 456 | name = "cxx" 457 | version = "1.0.86" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" 460 | dependencies = [ 461 | "cc", 462 | "cxxbridge-flags", 463 | "cxxbridge-macro", 464 | "link-cplusplus", 465 | ] 466 | 467 | [[package]] 468 | name = "cxx-build" 469 | version = "1.0.86" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" 472 | dependencies = [ 473 | "cc", 474 | "codespan-reporting", 475 | "once_cell", 476 | "proc-macro2", 477 | "quote", 478 | "scratch", 479 | "syn", 480 | ] 481 | 482 | [[package]] 483 | name = "cxxbridge-flags" 484 | version = "1.0.86" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" 487 | 488 | [[package]] 489 | name = "cxxbridge-macro" 490 | version = "1.0.86" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" 493 | dependencies = [ 494 | "proc-macro2", 495 | "quote", 496 | "syn", 497 | ] 498 | 499 | [[package]] 500 | name = "derive_more" 501 | version = "0.99.17" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 504 | dependencies = [ 505 | "convert_case", 506 | "proc-macro2", 507 | "quote", 508 | "rustc_version", 509 | "syn", 510 | ] 511 | 512 | [[package]] 513 | name = "digest" 514 | version = "0.10.6" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" 517 | dependencies = [ 518 | "block-buffer", 519 | "crypto-common", 520 | ] 521 | 522 | [[package]] 523 | name = "dotenv" 524 | version = "0.15.0" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 527 | 528 | [[package]] 529 | name = "encoding_rs" 530 | version = "0.8.31" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 533 | dependencies = [ 534 | "cfg-if", 535 | ] 536 | 537 | [[package]] 538 | name = "env_logger" 539 | version = "0.10.0" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" 542 | dependencies = [ 543 | "humantime", 544 | "is-terminal", 545 | "log", 546 | "regex", 547 | "termcolor", 548 | ] 549 | 550 | [[package]] 551 | name = "errno" 552 | version = "0.2.8" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 555 | dependencies = [ 556 | "errno-dragonfly", 557 | "libc", 558 | "winapi", 559 | ] 560 | 561 | [[package]] 562 | name = "errno-dragonfly" 563 | version = "0.1.2" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 566 | dependencies = [ 567 | "cc", 568 | "libc", 569 | ] 570 | 571 | [[package]] 572 | name = "fastrand" 573 | version = "1.8.0" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" 576 | dependencies = [ 577 | "instant", 578 | ] 579 | 580 | [[package]] 581 | name = "flate2" 582 | version = "1.0.25" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" 585 | dependencies = [ 586 | "crc32fast", 587 | "miniz_oxide", 588 | ] 589 | 590 | [[package]] 591 | name = "fnv" 592 | version = "1.0.7" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 595 | 596 | [[package]] 597 | name = "foreign-types" 598 | version = "0.3.2" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 601 | dependencies = [ 602 | "foreign-types-shared", 603 | ] 604 | 605 | [[package]] 606 | name = "foreign-types-shared" 607 | version = "0.1.1" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 610 | 611 | [[package]] 612 | name = "form_urlencoded" 613 | version = "1.1.0" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" 616 | dependencies = [ 617 | "percent-encoding", 618 | ] 619 | 620 | [[package]] 621 | name = "futures-channel" 622 | version = "0.3.25" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" 625 | dependencies = [ 626 | "futures-core", 627 | ] 628 | 629 | [[package]] 630 | name = "futures-core" 631 | version = "0.3.25" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" 634 | 635 | [[package]] 636 | name = "futures-sink" 637 | version = "0.3.25" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" 640 | 641 | [[package]] 642 | name = "futures-task" 643 | version = "0.3.25" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" 646 | 647 | [[package]] 648 | name = "futures-util" 649 | version = "0.3.25" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" 652 | dependencies = [ 653 | "futures-core", 654 | "futures-task", 655 | "pin-project-lite", 656 | "pin-utils", 657 | ] 658 | 659 | [[package]] 660 | name = "generic-array" 661 | version = "0.14.6" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 664 | dependencies = [ 665 | "typenum", 666 | "version_check", 667 | ] 668 | 669 | [[package]] 670 | name = "getrandom" 671 | version = "0.2.8" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 674 | dependencies = [ 675 | "cfg-if", 676 | "libc", 677 | "wasi 0.11.0+wasi-snapshot-preview1", 678 | ] 679 | 680 | [[package]] 681 | name = "google-github-oauth2-rust" 682 | version = "0.1.0" 683 | dependencies = [ 684 | "actix-cors", 685 | "actix-files", 686 | "actix-web", 687 | "chrono", 688 | "dotenv", 689 | "env_logger", 690 | "jsonwebtoken", 691 | "reqwest", 692 | "serde", 693 | "serde_json", 694 | "uuid", 695 | ] 696 | 697 | [[package]] 698 | name = "h2" 699 | version = "0.3.15" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" 702 | dependencies = [ 703 | "bytes", 704 | "fnv", 705 | "futures-core", 706 | "futures-sink", 707 | "futures-util", 708 | "http", 709 | "indexmap", 710 | "slab", 711 | "tokio", 712 | "tokio-util", 713 | "tracing", 714 | ] 715 | 716 | [[package]] 717 | name = "hashbrown" 718 | version = "0.12.3" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 721 | 722 | [[package]] 723 | name = "hermit-abi" 724 | version = "0.2.6" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" 727 | dependencies = [ 728 | "libc", 729 | ] 730 | 731 | [[package]] 732 | name = "http" 733 | version = "0.2.8" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 736 | dependencies = [ 737 | "bytes", 738 | "fnv", 739 | "itoa", 740 | ] 741 | 742 | [[package]] 743 | name = "http-body" 744 | version = "0.4.5" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 747 | dependencies = [ 748 | "bytes", 749 | "http", 750 | "pin-project-lite", 751 | ] 752 | 753 | [[package]] 754 | name = "http-range" 755 | version = "0.1.5" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" 758 | 759 | [[package]] 760 | name = "httparse" 761 | version = "1.8.0" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 764 | 765 | [[package]] 766 | name = "httpdate" 767 | version = "1.0.2" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 770 | 771 | [[package]] 772 | name = "humantime" 773 | version = "2.1.0" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 776 | 777 | [[package]] 778 | name = "hyper" 779 | version = "0.14.23" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" 782 | dependencies = [ 783 | "bytes", 784 | "futures-channel", 785 | "futures-core", 786 | "futures-util", 787 | "h2", 788 | "http", 789 | "http-body", 790 | "httparse", 791 | "httpdate", 792 | "itoa", 793 | "pin-project-lite", 794 | "socket2", 795 | "tokio", 796 | "tower-service", 797 | "tracing", 798 | "want", 799 | ] 800 | 801 | [[package]] 802 | name = "hyper-tls" 803 | version = "0.5.0" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 806 | dependencies = [ 807 | "bytes", 808 | "hyper", 809 | "native-tls", 810 | "tokio", 811 | "tokio-native-tls", 812 | ] 813 | 814 | [[package]] 815 | name = "iana-time-zone" 816 | version = "0.1.53" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" 819 | dependencies = [ 820 | "android_system_properties", 821 | "core-foundation-sys", 822 | "iana-time-zone-haiku", 823 | "js-sys", 824 | "wasm-bindgen", 825 | "winapi", 826 | ] 827 | 828 | [[package]] 829 | name = "iana-time-zone-haiku" 830 | version = "0.1.1" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" 833 | dependencies = [ 834 | "cxx", 835 | "cxx-build", 836 | ] 837 | 838 | [[package]] 839 | name = "idna" 840 | version = "0.3.0" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" 843 | dependencies = [ 844 | "unicode-bidi", 845 | "unicode-normalization", 846 | ] 847 | 848 | [[package]] 849 | name = "indexmap" 850 | version = "1.9.2" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 853 | dependencies = [ 854 | "autocfg", 855 | "hashbrown", 856 | ] 857 | 858 | [[package]] 859 | name = "instant" 860 | version = "0.1.12" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 863 | dependencies = [ 864 | "cfg-if", 865 | ] 866 | 867 | [[package]] 868 | name = "io-lifetimes" 869 | version = "1.0.4" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" 872 | dependencies = [ 873 | "libc", 874 | "windows-sys", 875 | ] 876 | 877 | [[package]] 878 | name = "ipnet" 879 | version = "2.7.1" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" 882 | 883 | [[package]] 884 | name = "is-terminal" 885 | version = "0.4.2" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" 888 | dependencies = [ 889 | "hermit-abi", 890 | "io-lifetimes", 891 | "rustix", 892 | "windows-sys", 893 | ] 894 | 895 | [[package]] 896 | name = "itoa" 897 | version = "1.0.5" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" 900 | 901 | [[package]] 902 | name = "jobserver" 903 | version = "0.1.25" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" 906 | dependencies = [ 907 | "libc", 908 | ] 909 | 910 | [[package]] 911 | name = "js-sys" 912 | version = "0.3.60" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" 915 | dependencies = [ 916 | "wasm-bindgen", 917 | ] 918 | 919 | [[package]] 920 | name = "jsonwebtoken" 921 | version = "8.2.0" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "09f4f04699947111ec1733e71778d763555737579e44b85844cae8e1940a1828" 924 | dependencies = [ 925 | "base64 0.13.1", 926 | "pem", 927 | "ring", 928 | "serde", 929 | "serde_json", 930 | "simple_asn1", 931 | ] 932 | 933 | [[package]] 934 | name = "language-tags" 935 | version = "0.3.2" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" 938 | 939 | [[package]] 940 | name = "lazy_static" 941 | version = "1.4.0" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 944 | 945 | [[package]] 946 | name = "libc" 947 | version = "0.2.139" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 950 | 951 | [[package]] 952 | name = "link-cplusplus" 953 | version = "1.0.8" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" 956 | dependencies = [ 957 | "cc", 958 | ] 959 | 960 | [[package]] 961 | name = "linux-raw-sys" 962 | version = "0.1.4" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" 965 | 966 | [[package]] 967 | name = "local-channel" 968 | version = "0.1.3" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" 971 | dependencies = [ 972 | "futures-core", 973 | "futures-sink", 974 | "futures-util", 975 | "local-waker", 976 | ] 977 | 978 | [[package]] 979 | name = "local-waker" 980 | version = "0.1.3" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" 983 | 984 | [[package]] 985 | name = "lock_api" 986 | version = "0.4.9" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" 989 | dependencies = [ 990 | "autocfg", 991 | "scopeguard", 992 | ] 993 | 994 | [[package]] 995 | name = "log" 996 | version = "0.4.17" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 999 | dependencies = [ 1000 | "cfg-if", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "memchr" 1005 | version = "2.5.0" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 1008 | 1009 | [[package]] 1010 | name = "mime" 1011 | version = "0.3.16" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 1014 | 1015 | [[package]] 1016 | name = "mime_guess" 1017 | version = "2.0.4" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 1020 | dependencies = [ 1021 | "mime", 1022 | "unicase", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "miniz_oxide" 1027 | version = "0.6.2" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" 1030 | dependencies = [ 1031 | "adler", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "mio" 1036 | version = "0.8.5" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" 1039 | dependencies = [ 1040 | "libc", 1041 | "log", 1042 | "wasi 0.11.0+wasi-snapshot-preview1", 1043 | "windows-sys", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "native-tls" 1048 | version = "0.2.11" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 1051 | dependencies = [ 1052 | "lazy_static", 1053 | "libc", 1054 | "log", 1055 | "openssl", 1056 | "openssl-probe", 1057 | "openssl-sys", 1058 | "schannel", 1059 | "security-framework", 1060 | "security-framework-sys", 1061 | "tempfile", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "num-bigint" 1066 | version = "0.4.3" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 1069 | dependencies = [ 1070 | "autocfg", 1071 | "num-integer", 1072 | "num-traits", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "num-integer" 1077 | version = "0.1.45" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 1080 | dependencies = [ 1081 | "autocfg", 1082 | "num-traits", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "num-traits" 1087 | version = "0.2.15" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 1090 | dependencies = [ 1091 | "autocfg", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "num_cpus" 1096 | version = "1.15.0" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" 1099 | dependencies = [ 1100 | "hermit-abi", 1101 | "libc", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "once_cell" 1106 | version = "1.17.0" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" 1109 | 1110 | [[package]] 1111 | name = "openssl" 1112 | version = "0.10.45" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" 1115 | dependencies = [ 1116 | "bitflags", 1117 | "cfg-if", 1118 | "foreign-types", 1119 | "libc", 1120 | "once_cell", 1121 | "openssl-macros", 1122 | "openssl-sys", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "openssl-macros" 1127 | version = "0.1.0" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" 1130 | dependencies = [ 1131 | "proc-macro2", 1132 | "quote", 1133 | "syn", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "openssl-probe" 1138 | version = "0.1.5" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1141 | 1142 | [[package]] 1143 | name = "openssl-sys" 1144 | version = "0.9.80" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" 1147 | dependencies = [ 1148 | "autocfg", 1149 | "cc", 1150 | "libc", 1151 | "pkg-config", 1152 | "vcpkg", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "parking_lot" 1157 | version = "0.12.1" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1160 | dependencies = [ 1161 | "lock_api", 1162 | "parking_lot_core", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "parking_lot_core" 1167 | version = "0.9.6" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" 1170 | dependencies = [ 1171 | "cfg-if", 1172 | "libc", 1173 | "redox_syscall", 1174 | "smallvec", 1175 | "windows-sys", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "paste" 1180 | version = "1.0.11" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" 1183 | 1184 | [[package]] 1185 | name = "pem" 1186 | version = "1.1.1" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" 1189 | dependencies = [ 1190 | "base64 0.13.1", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "percent-encoding" 1195 | version = "2.2.0" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 1198 | 1199 | [[package]] 1200 | name = "pin-project-lite" 1201 | version = "0.2.9" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 1204 | 1205 | [[package]] 1206 | name = "pin-utils" 1207 | version = "0.1.0" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1210 | 1211 | [[package]] 1212 | name = "pkg-config" 1213 | version = "0.3.26" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" 1216 | 1217 | [[package]] 1218 | name = "ppv-lite86" 1219 | version = "0.2.17" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1222 | 1223 | [[package]] 1224 | name = "proc-macro2" 1225 | version = "1.0.50" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" 1228 | dependencies = [ 1229 | "unicode-ident", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "quote" 1234 | version = "1.0.23" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 1237 | dependencies = [ 1238 | "proc-macro2", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "rand" 1243 | version = "0.8.5" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1246 | dependencies = [ 1247 | "libc", 1248 | "rand_chacha", 1249 | "rand_core", 1250 | ] 1251 | 1252 | [[package]] 1253 | name = "rand_chacha" 1254 | version = "0.3.1" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1257 | dependencies = [ 1258 | "ppv-lite86", 1259 | "rand_core", 1260 | ] 1261 | 1262 | [[package]] 1263 | name = "rand_core" 1264 | version = "0.6.4" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1267 | dependencies = [ 1268 | "getrandom", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "redox_syscall" 1273 | version = "0.2.16" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 1276 | dependencies = [ 1277 | "bitflags", 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "regex" 1282 | version = "1.7.1" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" 1285 | dependencies = [ 1286 | "aho-corasick", 1287 | "memchr", 1288 | "regex-syntax", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "regex-syntax" 1293 | version = "0.6.28" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 1296 | 1297 | [[package]] 1298 | name = "remove_dir_all" 1299 | version = "0.5.3" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1302 | dependencies = [ 1303 | "winapi", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "reqwest" 1308 | version = "0.11.14" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" 1311 | dependencies = [ 1312 | "base64 0.21.0", 1313 | "bytes", 1314 | "encoding_rs", 1315 | "futures-core", 1316 | "futures-util", 1317 | "h2", 1318 | "http", 1319 | "http-body", 1320 | "hyper", 1321 | "hyper-tls", 1322 | "ipnet", 1323 | "js-sys", 1324 | "log", 1325 | "mime", 1326 | "native-tls", 1327 | "once_cell", 1328 | "percent-encoding", 1329 | "pin-project-lite", 1330 | "serde", 1331 | "serde_json", 1332 | "serde_urlencoded", 1333 | "tokio", 1334 | "tokio-native-tls", 1335 | "tower-service", 1336 | "url", 1337 | "wasm-bindgen", 1338 | "wasm-bindgen-futures", 1339 | "web-sys", 1340 | "winreg", 1341 | ] 1342 | 1343 | [[package]] 1344 | name = "ring" 1345 | version = "0.16.20" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1348 | dependencies = [ 1349 | "cc", 1350 | "libc", 1351 | "once_cell", 1352 | "spin", 1353 | "untrusted", 1354 | "web-sys", 1355 | "winapi", 1356 | ] 1357 | 1358 | [[package]] 1359 | name = "rustc_version" 1360 | version = "0.4.0" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1363 | dependencies = [ 1364 | "semver", 1365 | ] 1366 | 1367 | [[package]] 1368 | name = "rustix" 1369 | version = "0.36.7" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" 1372 | dependencies = [ 1373 | "bitflags", 1374 | "errno", 1375 | "io-lifetimes", 1376 | "libc", 1377 | "linux-raw-sys", 1378 | "windows-sys", 1379 | ] 1380 | 1381 | [[package]] 1382 | name = "ryu" 1383 | version = "1.0.12" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" 1386 | 1387 | [[package]] 1388 | name = "schannel" 1389 | version = "0.1.21" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" 1392 | dependencies = [ 1393 | "windows-sys", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "scopeguard" 1398 | version = "1.1.0" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1401 | 1402 | [[package]] 1403 | name = "scratch" 1404 | version = "1.0.3" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" 1407 | 1408 | [[package]] 1409 | name = "security-framework" 1410 | version = "2.8.0" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "645926f31b250a2dca3c232496c2d898d91036e45ca0e97e0e2390c54e11be36" 1413 | dependencies = [ 1414 | "bitflags", 1415 | "core-foundation", 1416 | "core-foundation-sys", 1417 | "libc", 1418 | "security-framework-sys", 1419 | ] 1420 | 1421 | [[package]] 1422 | name = "security-framework-sys" 1423 | version = "2.8.0" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" 1426 | dependencies = [ 1427 | "core-foundation-sys", 1428 | "libc", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "semver" 1433 | version = "1.0.16" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" 1436 | 1437 | [[package]] 1438 | name = "serde" 1439 | version = "1.0.152" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" 1442 | dependencies = [ 1443 | "serde_derive", 1444 | ] 1445 | 1446 | [[package]] 1447 | name = "serde_derive" 1448 | version = "1.0.152" 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" 1450 | checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" 1451 | dependencies = [ 1452 | "proc-macro2", 1453 | "quote", 1454 | "syn", 1455 | ] 1456 | 1457 | [[package]] 1458 | name = "serde_json" 1459 | version = "1.0.91" 1460 | source = "registry+https://github.com/rust-lang/crates.io-index" 1461 | checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" 1462 | dependencies = [ 1463 | "itoa", 1464 | "ryu", 1465 | "serde", 1466 | ] 1467 | 1468 | [[package]] 1469 | name = "serde_urlencoded" 1470 | version = "0.7.1" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1473 | dependencies = [ 1474 | "form_urlencoded", 1475 | "itoa", 1476 | "ryu", 1477 | "serde", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "sha1" 1482 | version = "0.10.5" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 1485 | dependencies = [ 1486 | "cfg-if", 1487 | "cpufeatures", 1488 | "digest", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "signal-hook-registry" 1493 | version = "1.4.0" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1496 | dependencies = [ 1497 | "libc", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "simple_asn1" 1502 | version = "0.6.2" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" 1505 | dependencies = [ 1506 | "num-bigint", 1507 | "num-traits", 1508 | "thiserror", 1509 | "time 0.3.17", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "slab" 1514 | version = "0.4.7" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 1517 | dependencies = [ 1518 | "autocfg", 1519 | ] 1520 | 1521 | [[package]] 1522 | name = "smallvec" 1523 | version = "1.10.0" 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" 1525 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 1526 | 1527 | [[package]] 1528 | name = "socket2" 1529 | version = "0.4.7" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" 1532 | dependencies = [ 1533 | "libc", 1534 | "winapi", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "spin" 1539 | version = "0.5.2" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1542 | 1543 | [[package]] 1544 | name = "syn" 1545 | version = "1.0.107" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" 1548 | dependencies = [ 1549 | "proc-macro2", 1550 | "quote", 1551 | "unicode-ident", 1552 | ] 1553 | 1554 | [[package]] 1555 | name = "tempfile" 1556 | version = "3.3.0" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 1559 | dependencies = [ 1560 | "cfg-if", 1561 | "fastrand", 1562 | "libc", 1563 | "redox_syscall", 1564 | "remove_dir_all", 1565 | "winapi", 1566 | ] 1567 | 1568 | [[package]] 1569 | name = "termcolor" 1570 | version = "1.2.0" 1571 | source = "registry+https://github.com/rust-lang/crates.io-index" 1572 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 1573 | dependencies = [ 1574 | "winapi-util", 1575 | ] 1576 | 1577 | [[package]] 1578 | name = "thiserror" 1579 | version = "1.0.38" 1580 | source = "registry+https://github.com/rust-lang/crates.io-index" 1581 | checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" 1582 | dependencies = [ 1583 | "thiserror-impl", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "thiserror-impl" 1588 | version = "1.0.38" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" 1591 | dependencies = [ 1592 | "proc-macro2", 1593 | "quote", 1594 | "syn", 1595 | ] 1596 | 1597 | [[package]] 1598 | name = "time" 1599 | version = "0.1.45" 1600 | source = "registry+https://github.com/rust-lang/crates.io-index" 1601 | checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" 1602 | dependencies = [ 1603 | "libc", 1604 | "wasi 0.10.0+wasi-snapshot-preview1", 1605 | "winapi", 1606 | ] 1607 | 1608 | [[package]] 1609 | name = "time" 1610 | version = "0.3.17" 1611 | source = "registry+https://github.com/rust-lang/crates.io-index" 1612 | checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" 1613 | dependencies = [ 1614 | "itoa", 1615 | "serde", 1616 | "time-core", 1617 | "time-macros", 1618 | ] 1619 | 1620 | [[package]] 1621 | name = "time-core" 1622 | version = "0.1.0" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" 1625 | 1626 | [[package]] 1627 | name = "time-macros" 1628 | version = "0.2.6" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" 1631 | dependencies = [ 1632 | "time-core", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "tinyvec" 1637 | version = "1.6.0" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1640 | dependencies = [ 1641 | "tinyvec_macros", 1642 | ] 1643 | 1644 | [[package]] 1645 | name = "tinyvec_macros" 1646 | version = "0.1.0" 1647 | source = "registry+https://github.com/rust-lang/crates.io-index" 1648 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1649 | 1650 | [[package]] 1651 | name = "tokio" 1652 | version = "1.24.2" 1653 | source = "registry+https://github.com/rust-lang/crates.io-index" 1654 | checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" 1655 | dependencies = [ 1656 | "autocfg", 1657 | "bytes", 1658 | "libc", 1659 | "memchr", 1660 | "mio", 1661 | "parking_lot", 1662 | "pin-project-lite", 1663 | "signal-hook-registry", 1664 | "socket2", 1665 | "windows-sys", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "tokio-native-tls" 1670 | version = "0.3.0" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1673 | dependencies = [ 1674 | "native-tls", 1675 | "tokio", 1676 | ] 1677 | 1678 | [[package]] 1679 | name = "tokio-util" 1680 | version = "0.7.4" 1681 | source = "registry+https://github.com/rust-lang/crates.io-index" 1682 | checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" 1683 | dependencies = [ 1684 | "bytes", 1685 | "futures-core", 1686 | "futures-sink", 1687 | "pin-project-lite", 1688 | "tokio", 1689 | "tracing", 1690 | ] 1691 | 1692 | [[package]] 1693 | name = "tower-service" 1694 | version = "0.3.2" 1695 | source = "registry+https://github.com/rust-lang/crates.io-index" 1696 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1697 | 1698 | [[package]] 1699 | name = "tracing" 1700 | version = "0.1.37" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1703 | dependencies = [ 1704 | "cfg-if", 1705 | "log", 1706 | "pin-project-lite", 1707 | "tracing-core", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "tracing-core" 1712 | version = "0.1.30" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 1715 | dependencies = [ 1716 | "once_cell", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "try-lock" 1721 | version = "0.2.4" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 1724 | 1725 | [[package]] 1726 | name = "typenum" 1727 | version = "1.16.0" 1728 | source = "registry+https://github.com/rust-lang/crates.io-index" 1729 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1730 | 1731 | [[package]] 1732 | name = "unicase" 1733 | version = "2.6.0" 1734 | source = "registry+https://github.com/rust-lang/crates.io-index" 1735 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1736 | dependencies = [ 1737 | "version_check", 1738 | ] 1739 | 1740 | [[package]] 1741 | name = "unicode-bidi" 1742 | version = "0.3.9" 1743 | source = "registry+https://github.com/rust-lang/crates.io-index" 1744 | checksum = "0046be40136ef78dc325e0edefccf84ccddacd0afcc1ca54103fa3c61bbdab1d" 1745 | 1746 | [[package]] 1747 | name = "unicode-ident" 1748 | version = "1.0.6" 1749 | source = "registry+https://github.com/rust-lang/crates.io-index" 1750 | checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" 1751 | 1752 | [[package]] 1753 | name = "unicode-normalization" 1754 | version = "0.1.22" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1757 | dependencies = [ 1758 | "tinyvec", 1759 | ] 1760 | 1761 | [[package]] 1762 | name = "unicode-width" 1763 | version = "0.1.10" 1764 | source = "registry+https://github.com/rust-lang/crates.io-index" 1765 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 1766 | 1767 | [[package]] 1768 | name = "untrusted" 1769 | version = "0.7.1" 1770 | source = "registry+https://github.com/rust-lang/crates.io-index" 1771 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1772 | 1773 | [[package]] 1774 | name = "url" 1775 | version = "2.3.1" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" 1778 | dependencies = [ 1779 | "form_urlencoded", 1780 | "idna", 1781 | "percent-encoding", 1782 | ] 1783 | 1784 | [[package]] 1785 | name = "uuid" 1786 | version = "1.2.2" 1787 | source = "registry+https://github.com/rust-lang/crates.io-index" 1788 | checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" 1789 | dependencies = [ 1790 | "getrandom", 1791 | ] 1792 | 1793 | [[package]] 1794 | name = "vcpkg" 1795 | version = "0.2.15" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1798 | 1799 | [[package]] 1800 | name = "version_check" 1801 | version = "0.9.4" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1804 | 1805 | [[package]] 1806 | name = "want" 1807 | version = "0.3.0" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1810 | dependencies = [ 1811 | "log", 1812 | "try-lock", 1813 | ] 1814 | 1815 | [[package]] 1816 | name = "wasi" 1817 | version = "0.10.0+wasi-snapshot-preview1" 1818 | source = "registry+https://github.com/rust-lang/crates.io-index" 1819 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1820 | 1821 | [[package]] 1822 | name = "wasi" 1823 | version = "0.11.0+wasi-snapshot-preview1" 1824 | source = "registry+https://github.com/rust-lang/crates.io-index" 1825 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1826 | 1827 | [[package]] 1828 | name = "wasm-bindgen" 1829 | version = "0.2.83" 1830 | source = "registry+https://github.com/rust-lang/crates.io-index" 1831 | checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" 1832 | dependencies = [ 1833 | "cfg-if", 1834 | "wasm-bindgen-macro", 1835 | ] 1836 | 1837 | [[package]] 1838 | name = "wasm-bindgen-backend" 1839 | version = "0.2.83" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" 1842 | dependencies = [ 1843 | "bumpalo", 1844 | "log", 1845 | "once_cell", 1846 | "proc-macro2", 1847 | "quote", 1848 | "syn", 1849 | "wasm-bindgen-shared", 1850 | ] 1851 | 1852 | [[package]] 1853 | name = "wasm-bindgen-futures" 1854 | version = "0.4.33" 1855 | source = "registry+https://github.com/rust-lang/crates.io-index" 1856 | checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" 1857 | dependencies = [ 1858 | "cfg-if", 1859 | "js-sys", 1860 | "wasm-bindgen", 1861 | "web-sys", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "wasm-bindgen-macro" 1866 | version = "0.2.83" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" 1869 | dependencies = [ 1870 | "quote", 1871 | "wasm-bindgen-macro-support", 1872 | ] 1873 | 1874 | [[package]] 1875 | name = "wasm-bindgen-macro-support" 1876 | version = "0.2.83" 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" 1878 | checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" 1879 | dependencies = [ 1880 | "proc-macro2", 1881 | "quote", 1882 | "syn", 1883 | "wasm-bindgen-backend", 1884 | "wasm-bindgen-shared", 1885 | ] 1886 | 1887 | [[package]] 1888 | name = "wasm-bindgen-shared" 1889 | version = "0.2.83" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" 1892 | 1893 | [[package]] 1894 | name = "web-sys" 1895 | version = "0.3.60" 1896 | source = "registry+https://github.com/rust-lang/crates.io-index" 1897 | checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" 1898 | dependencies = [ 1899 | "js-sys", 1900 | "wasm-bindgen", 1901 | ] 1902 | 1903 | [[package]] 1904 | name = "winapi" 1905 | version = "0.3.9" 1906 | source = "registry+https://github.com/rust-lang/crates.io-index" 1907 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1908 | dependencies = [ 1909 | "winapi-i686-pc-windows-gnu", 1910 | "winapi-x86_64-pc-windows-gnu", 1911 | ] 1912 | 1913 | [[package]] 1914 | name = "winapi-i686-pc-windows-gnu" 1915 | version = "0.4.0" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1918 | 1919 | [[package]] 1920 | name = "winapi-util" 1921 | version = "0.1.5" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1924 | dependencies = [ 1925 | "winapi", 1926 | ] 1927 | 1928 | [[package]] 1929 | name = "winapi-x86_64-pc-windows-gnu" 1930 | version = "0.4.0" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1933 | 1934 | [[package]] 1935 | name = "windows-sys" 1936 | version = "0.42.0" 1937 | source = "registry+https://github.com/rust-lang/crates.io-index" 1938 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 1939 | dependencies = [ 1940 | "windows_aarch64_gnullvm", 1941 | "windows_aarch64_msvc", 1942 | "windows_i686_gnu", 1943 | "windows_i686_msvc", 1944 | "windows_x86_64_gnu", 1945 | "windows_x86_64_gnullvm", 1946 | "windows_x86_64_msvc", 1947 | ] 1948 | 1949 | [[package]] 1950 | name = "windows_aarch64_gnullvm" 1951 | version = "0.42.1" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" 1954 | 1955 | [[package]] 1956 | name = "windows_aarch64_msvc" 1957 | version = "0.42.1" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" 1960 | 1961 | [[package]] 1962 | name = "windows_i686_gnu" 1963 | version = "0.42.1" 1964 | source = "registry+https://github.com/rust-lang/crates.io-index" 1965 | checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" 1966 | 1967 | [[package]] 1968 | name = "windows_i686_msvc" 1969 | version = "0.42.1" 1970 | source = "registry+https://github.com/rust-lang/crates.io-index" 1971 | checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" 1972 | 1973 | [[package]] 1974 | name = "windows_x86_64_gnu" 1975 | version = "0.42.1" 1976 | source = "registry+https://github.com/rust-lang/crates.io-index" 1977 | checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" 1978 | 1979 | [[package]] 1980 | name = "windows_x86_64_gnullvm" 1981 | version = "0.42.1" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" 1984 | 1985 | [[package]] 1986 | name = "windows_x86_64_msvc" 1987 | version = "0.42.1" 1988 | source = "registry+https://github.com/rust-lang/crates.io-index" 1989 | checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" 1990 | 1991 | [[package]] 1992 | name = "winreg" 1993 | version = "0.10.1" 1994 | source = "registry+https://github.com/rust-lang/crates.io-index" 1995 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" 1996 | dependencies = [ 1997 | "winapi", 1998 | ] 1999 | 2000 | [[package]] 2001 | name = "zstd" 2002 | version = "0.11.2+zstd.1.5.2" 2003 | source = "registry+https://github.com/rust-lang/crates.io-index" 2004 | checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" 2005 | dependencies = [ 2006 | "zstd-safe", 2007 | ] 2008 | 2009 | [[package]] 2010 | name = "zstd-safe" 2011 | version = "5.0.2+zstd.1.5.2" 2012 | source = "registry+https://github.com/rust-lang/crates.io-index" 2013 | checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" 2014 | dependencies = [ 2015 | "libc", 2016 | "zstd-sys", 2017 | ] 2018 | 2019 | [[package]] 2020 | name = "zstd-sys" 2021 | version = "2.0.5+zstd.1.5.2" 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" 2023 | checksum = "edc50ffce891ad571e9f9afe5039c4837bede781ac4bb13052ed7ae695518596" 2024 | dependencies = [ 2025 | "cc", 2026 | "libc", 2027 | "pkg-config", 2028 | ] 2029 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "google-github-oauth2-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | actix-cors = "0.6.4" 10 | actix-files = "0.6.2" 11 | actix-web = "4.2.1" 12 | chrono = { version = "0.4.23", features = ["serde"] } 13 | dotenv = "0.15.0" 14 | env_logger = "0.10.0" 15 | jsonwebtoken = "8.2.0" 16 | reqwest = { version = "0.11.14", features = ["json"] } 17 | serde = { version = "1.0.152", features = ["derive"] } 18 | serde_json = "1.0.91" 19 | uuid = { version = "1.2.2", features = ["v4"] } 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start-server: 2 | cargo watch -q -c -w src/ -x run 3 | 4 | install: 5 | cargo add actix-web 6 | cargo add actix-cors 7 | cargo add serde --features derive 8 | cargo add serde_json 9 | cargo add chrono --features serde 10 | cargo add env_logger 11 | cargo add jsonwebtoken 12 | cargo add dotenv 13 | cargo add uuid --features v4 14 | cargo add reqwest --features json 15 | # HotReload 16 | cargo install cargo-watch -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to Implement Google OAuth2 in Rust 2 | 3 | This article will teach you how to integrate Google OAuth2 into your Rust application, all without relying on third-party OAuth crates such as [https://crates.io/crates/oauth2](https://crates.io/crates/oauth2). We'll be utilizing the Actix-Web HTTP framework, known for its high performance, to power the API. Additionally, we'll store data in a centralized in-memory database. 4 | 5 | ![How to Implement Google OAuth2 in Rust](https://codevoweb.com/wp-content/uploads/2023/02/How-to-Implement-Google-OAuth2-in-Rust.webp) 6 | 7 | ## Topics Covered 8 | 9 | - Run the Rust Google OAuth2 Project 10 | - Run the Rust OAuth2 API with a React.js App 11 | - Setup the Rust Project with Cargo 12 | - Obtain the Google OAuth2 Credentials 13 | - Load the Environment Variables 14 | - Create an In-memory Database 15 | - Create the Response Structs 16 | - Get the Google OAuth2 Access Token and User Info 17 | - Create the Actix-Web Route Handlers 18 | - Register User Actix-Web Route Handler 19 | - Login User Actix-Web Route Handler 20 | - Implement the Google OAuth2 21 | - Logout User Actix-Web Route Handler 22 | - Retrieve the Authenticated User 23 | - Merge the Actix-Web Route Handlers 24 | - Register the Actix-Web Config and Add CORS 25 | - Test the Rust Google OAuth Flow 26 | - Register User 27 | - Login User 28 | - Authenticate with Google OAuth 29 | - Get Profile Information 30 | 31 | Read the entire article here: [https://codevoweb.com/how-to-implement-google-oauth2-in-rust/](https://codevoweb.com/how-to-implement-google-oauth2-in-rust/) 32 | 33 | -------------------------------------------------------------------------------- /public/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpcodevo/google-github-oauth2-rust/dc123e049e0adcd63e06a81249f66503079aa334/public/default.png -------------------------------------------------------------------------------- /src/authenticate_token.rs: -------------------------------------------------------------------------------- 1 | use std::future::{ready, Ready}; 2 | 3 | use actix_web::{ 4 | dev::Payload, 5 | error::{Error as ActixWebError, ErrorUnauthorized}, 6 | http, web, FromRequest, HttpRequest, 7 | }; 8 | use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; 9 | use serde_json::json; 10 | 11 | use crate::model::{AppState, TokenClaims}; 12 | 13 | pub struct AuthenticationGuard { 14 | pub user_id: String, 15 | } 16 | 17 | impl FromRequest for AuthenticationGuard { 18 | type Error = ActixWebError; 19 | type Future = Ready>; 20 | 21 | fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { 22 | let token = req 23 | .cookie("token") 24 | .map(|c| c.value().to_string()) 25 | .or_else(|| { 26 | req.headers() 27 | .get(http::header::AUTHORIZATION) 28 | .map(|h| h.to_str().unwrap().split_at(7).1.to_string()) 29 | }); 30 | 31 | if token.is_none() { 32 | return ready(Err(ErrorUnauthorized( 33 | json!({"status": "fail", "message": "You are not logged in, please provide token"}), 34 | ))); 35 | } 36 | 37 | let data = req.app_data::>().unwrap(); 38 | 39 | let jwt_secret = data.env.jwt_secret.to_owned(); 40 | let decode = decode::( 41 | token.unwrap().as_str(), 42 | &DecodingKey::from_secret(jwt_secret.as_ref()), 43 | &Validation::new(Algorithm::HS256), 44 | ); 45 | 46 | match decode { 47 | Ok(token) => { 48 | let vec = data.db.lock().unwrap(); 49 | let user = vec 50 | .iter() 51 | .find(|user| user.id == Some(token.claims.sub.to_owned())); 52 | 53 | if user.is_none() { 54 | return ready(Err(ErrorUnauthorized( 55 | json!({"status": "fail", "message": "User belonging to this token no logger exists"}), 56 | ))); 57 | } 58 | 59 | ready(Ok(AuthenticationGuard { 60 | user_id: token.claims.sub, 61 | })) 62 | } 63 | Err(_) => ready(Err(ErrorUnauthorized( 64 | json!({"status": "fail", "message": "Invalid token or usre doesn't exists"}), 65 | ))), 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Config { 3 | pub client_origin: String, 4 | pub jwt_secret: String, 5 | pub jwt_expires_in: String, 6 | pub jwt_max_age: i64, 7 | pub google_oauth_client_id: String, 8 | pub google_oauth_client_secret: String, 9 | pub google_oauth_redirect_url: String, 10 | pub github_oauth_client_id: String, 11 | pub github_oauth_client_secret: String, 12 | pub github_oauth_redirect_url: String, 13 | } 14 | 15 | impl Config { 16 | pub fn init() -> Config { 17 | let client_origin = std::env::var("CLIENT_ORIGIN").expect("CLIENT_ORIGIN must be set"); 18 | let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); 19 | let jwt_expires_in = 20 | std::env::var("TOKEN_EXPIRED_IN").expect("TOKEN_EXPIRED_IN must be set"); 21 | let jwt_max_age = std::env::var("TOKEN_MAXAGE").expect("TOKEN_MAXAGE must be set"); 22 | let google_oauth_client_id = 23 | std::env::var("GOOGLE_OAUTH_CLIENT_ID").expect("GOOGLE_OAUTH_CLIENT_ID must be set"); 24 | let google_oauth_client_secret = std::env::var("GOOGLE_OAUTH_CLIENT_SECRET") 25 | .expect("GOOGLE_OAUTH_CLIENT_SECRET must be set"); 26 | let google_oauth_redirect_url = std::env::var("GOOGLE_OAUTH_REDIRECT_URL") 27 | .expect("GOOGLE_OAUTH_REDIRECT_URL must be set"); 28 | let github_oauth_client_id = 29 | std::env::var("GITHUB_OAUTH_CLIENT_ID").expect("GITHUB_OAUTH_CLIENT_ID must be set"); 30 | let github_oauth_client_secret = std::env::var("GITHUB_OAUTH_CLIENT_SECRET") 31 | .expect("GITHUB_OAUTH_CLIENT_SECRET must be set"); 32 | let github_oauth_redirect_url = std::env::var("GITHUB_OAUTH_REDIRECT_URL") 33 | .expect("GITHUB_OAUTH_REDIRECT_URL must be set"); 34 | 35 | Config { 36 | client_origin, 37 | jwt_secret, 38 | jwt_expires_in, 39 | jwt_max_age: jwt_max_age.parse::().unwrap(), 40 | google_oauth_client_id, 41 | google_oauth_client_secret, 42 | google_oauth_redirect_url, 43 | github_oauth_client_id, 44 | github_oauth_client_secret, 45 | github_oauth_redirect_url, 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/github_oauth.rs: -------------------------------------------------------------------------------- 1 | use actix_web::web; 2 | use reqwest::Client; 3 | use serde::Deserialize; 4 | use std::error::Error; 5 | 6 | use crate::model::AppState; 7 | 8 | #[derive(Deserialize)] 9 | pub struct GitHubOauthToken { 10 | pub access_token: String, 11 | } 12 | 13 | #[derive(Deserialize)] 14 | pub struct GitHubUserResult { 15 | pub login: String, 16 | pub avatar_url: String, 17 | pub email: String, 18 | } 19 | 20 | pub async fn get_github_oauth_token( 21 | authorization_code: &str, 22 | data: &web::Data, 23 | ) -> Result> { 24 | let client_secret = data.env.github_oauth_client_id.to_owned(); 25 | let client_id = data.env.github_oauth_client_secret.to_owned(); 26 | 27 | let root_url = "https://github.com/login/oauth/access_token"; 28 | 29 | let client = Client::new(); 30 | 31 | let params = [ 32 | ("client_id", client_id.as_str()), 33 | ("code", authorization_code), 34 | ("client_secret", client_secret.as_str()), 35 | ]; 36 | 37 | let response = client 38 | .post(root_url) 39 | .header("Accept", "application/json") 40 | .form(¶ms) 41 | .send() 42 | .await?; 43 | 44 | if response.status().is_success() { 45 | let oauth_response = response.json::().await?; 46 | Ok(oauth_response) 47 | } else { 48 | let message = "An error occurred while trying to retrieve the access token."; 49 | Err(From::from(message)) 50 | } 51 | } 52 | 53 | pub async fn get_github_user(access_token: &str) -> Result> { 54 | let root_url = "https://api.github.com/user"; 55 | 56 | let client = Client::new(); 57 | 58 | let response = client 59 | .get(root_url) 60 | .bearer_auth(access_token) 61 | .send() 62 | .await?; 63 | 64 | if response.status().is_success() { 65 | let user_info = response.json::().await?; 66 | Ok(user_info) 67 | } else { 68 | let message = "An error occurred while trying to retrieve user information."; 69 | Err(From::from(message)) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/google_oauth.rs: -------------------------------------------------------------------------------- 1 | use actix_web::web; 2 | use reqwest::{Client, Url}; 3 | use serde::Deserialize; 4 | use std::error::Error; 5 | 6 | use crate::model::AppState; 7 | 8 | #[derive(Deserialize)] 9 | pub struct OAuthResponse { 10 | pub access_token: String, 11 | pub id_token: String, 12 | } 13 | 14 | #[derive(Deserialize)] 15 | pub struct GoogleUserResult { 16 | pub id: String, 17 | pub email: String, 18 | pub verified_email: bool, 19 | pub name: String, 20 | pub given_name: String, 21 | pub family_name: String, 22 | pub picture: String, 23 | pub locale: String, 24 | } 25 | 26 | pub async fn request_token( 27 | authorization_code: &str, 28 | data: &web::Data, 29 | ) -> Result> { 30 | let redirect_url = data.env.google_oauth_redirect_url.to_owned(); 31 | let client_secret = data.env.google_oauth_client_secret.to_owned(); 32 | let client_id = data.env.google_oauth_client_id.to_owned(); 33 | 34 | let root_url = "https://oauth2.googleapis.com/token"; 35 | let client = Client::new(); 36 | 37 | let params = [ 38 | ("grant_type", "authorization_code"), 39 | ("redirect_uri", redirect_url.as_str()), 40 | ("client_id", client_id.as_str()), 41 | ("code", authorization_code), 42 | ("client_secret", client_secret.as_str()), 43 | ]; 44 | let response = client.post(root_url).form(¶ms).send().await?; 45 | 46 | if response.status().is_success() { 47 | let oauth_response = response.json::().await?; 48 | Ok(oauth_response) 49 | } else { 50 | let message = "An error occurred while trying to retrieve access token."; 51 | Err(From::from(message)) 52 | } 53 | } 54 | 55 | pub async fn get_google_user( 56 | access_token: &str, 57 | id_token: &str, 58 | ) -> Result> { 59 | let client = Client::new(); 60 | let mut url = Url::parse("https://www.googleapis.com/oauth2/v1/userinfo").unwrap(); 61 | url.query_pairs_mut().append_pair("alt", "json"); 62 | url.query_pairs_mut() 63 | .append_pair("access_token", access_token); 64 | 65 | let response = client.get(url).bearer_auth(id_token).send().await?; 66 | 67 | if response.status().is_success() { 68 | let user_info = response.json::().await?; 69 | Ok(user_info) 70 | } else { 71 | let message = "An error occurred while trying to retrieve user information."; 72 | Err(From::from(message)) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/handler.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | authenticate_token::AuthenticationGuard, 3 | github_oauth::{get_github_oauth_token, get_github_user}, 4 | google_oauth::{get_google_user, request_token}, 5 | model::{AppState, LoginUserSchema, QueryCode, RegisterUserSchema, TokenClaims, User}, 6 | response::{FilteredUser, UserData, UserResponse}, 7 | }; 8 | use actix_web::{ 9 | cookie::{time::Duration as ActixWebDuration, Cookie}, 10 | get, post, web, HttpResponse, Responder, 11 | }; 12 | use chrono::{prelude::*, Duration}; 13 | use jsonwebtoken::{encode, EncodingKey, Header}; 14 | use reqwest::header::LOCATION; 15 | use uuid::Uuid; 16 | 17 | #[get("/healthchecker")] 18 | async fn health_checker_handler() -> impl Responder { 19 | const MESSAGE: &str = "How to Implement Google and GitHub OAuth2 in Rust"; 20 | 21 | HttpResponse::Ok().json(serde_json::json!({"status": "success", "message": MESSAGE})) 22 | } 23 | 24 | #[post("/auth/register")] 25 | async fn register_user_handler( 26 | body: web::Json, 27 | data: web::Data, 28 | ) -> impl Responder { 29 | let mut vec = data.db.lock().unwrap(); 30 | 31 | let user = vec.iter().find(|user| user.email == body.email); 32 | 33 | if user.is_some() { 34 | return HttpResponse::Conflict() 35 | .json(serde_json::json!({"status": "fail","message": "Email already exist"})); 36 | } 37 | 38 | let uuid_id = Uuid::new_v4(); 39 | let datetime = Utc::now(); 40 | 41 | let user = User { 42 | id: Some(uuid_id.to_string()), 43 | name: body.name.to_owned(), 44 | verified: false, 45 | email: body.email.to_owned().to_lowercase(), 46 | provider: "local".to_string(), 47 | role: "user".to_string(), 48 | password: "".to_string(), 49 | photo: "default.png".to_string(), 50 | createdAt: Some(datetime), 51 | updatedAt: Some(datetime), 52 | }; 53 | 54 | vec.push(user.to_owned()); 55 | 56 | let json_response = UserResponse { 57 | status: "success".to_string(), 58 | data: UserData { 59 | user: user_to_response(&user), 60 | }, 61 | }; 62 | 63 | HttpResponse::Ok().json(json_response) 64 | } 65 | #[post("/auth/login")] 66 | async fn login_user_handler( 67 | body: web::Json, 68 | data: web::Data, 69 | ) -> impl Responder { 70 | let vec = data.db.lock().unwrap(); 71 | 72 | let user = vec 73 | .iter() 74 | .find(|user| user.email == body.email.to_lowercase()); 75 | 76 | if user.is_none() { 77 | return HttpResponse::BadRequest() 78 | .json(serde_json::json!({"status": "fail", "message": "Invalid email or password"})); 79 | } 80 | 81 | let user = user.unwrap().clone(); 82 | 83 | if user.provider == "Google" { 84 | return HttpResponse::Unauthorized() 85 | .json(serde_json::json!({"status": "fail", "message": "Use Google OAuth2 instead"})); 86 | } else if user.provider == "GitHub" { 87 | return HttpResponse::Unauthorized() 88 | .json(serde_json::json!({"status": "fail", "message": "Use GitHub OAuth instead"})); 89 | } 90 | 91 | let jwt_secret = data.env.jwt_secret.to_owned(); 92 | let now = Utc::now(); 93 | let iat = now.timestamp() as usize; 94 | let exp = (now + Duration::minutes(data.env.jwt_max_age)).timestamp() as usize; 95 | let claims: TokenClaims = TokenClaims { 96 | sub: user.id.unwrap(), 97 | exp, 98 | iat, 99 | }; 100 | 101 | let token = encode( 102 | &Header::default(), 103 | &claims, 104 | &EncodingKey::from_secret(jwt_secret.as_ref()), 105 | ) 106 | .unwrap(); 107 | 108 | let cookie = Cookie::build("token", token) 109 | .path("/") 110 | .max_age(ActixWebDuration::new(60 * data.env.jwt_max_age, 0)) 111 | .http_only(true) 112 | .finish(); 113 | 114 | HttpResponse::Ok() 115 | .cookie(cookie) 116 | .json(serde_json::json!({"status": "success"})) 117 | } 118 | 119 | #[get("/sessions/oauth/google")] 120 | async fn google_oauth_handler( 121 | query: web::Query, 122 | data: web::Data, 123 | ) -> impl Responder { 124 | let code = &query.code; 125 | let state = &query.state; 126 | 127 | if code.is_empty() { 128 | return HttpResponse::Unauthorized().json( 129 | serde_json::json!({"status": "fail", "message": "Authorization code not provided!"}), 130 | ); 131 | } 132 | 133 | let token_response = request_token(code.as_str(), &data).await; 134 | if token_response.is_err() { 135 | let message = token_response.err().unwrap().to_string(); 136 | return HttpResponse::BadGateway() 137 | .json(serde_json::json!({"status": "fail", "message": message})); 138 | } 139 | 140 | let token_response = token_response.unwrap(); 141 | let google_user = get_google_user(&token_response.access_token, &token_response.id_token).await; 142 | if google_user.is_err() { 143 | let message = google_user.err().unwrap().to_string(); 144 | return HttpResponse::BadGateway() 145 | .json(serde_json::json!({"status": "fail", "message": message})); 146 | } 147 | 148 | let google_user = google_user.unwrap(); 149 | 150 | let mut vec = data.db.lock().unwrap(); 151 | let email = google_user.email.to_lowercase(); 152 | let user = vec.iter_mut().find(|user| user.email == email); 153 | 154 | let user_id: String; 155 | 156 | if user.is_some() { 157 | let user = user.unwrap(); 158 | user_id = user.id.to_owned().unwrap(); 159 | user.email = email.to_owned(); 160 | user.photo = google_user.picture; 161 | user.updatedAt = Some(Utc::now()); 162 | } else { 163 | let datetime = Utc::now(); 164 | let id = Uuid::new_v4(); 165 | user_id = id.to_owned().to_string(); 166 | let user_data = User { 167 | id: Some(id.to_string()), 168 | name: google_user.name, 169 | verified: google_user.verified_email, 170 | email, 171 | provider: "Google".to_string(), 172 | role: "user".to_string(), 173 | password: "".to_string(), 174 | photo: google_user.picture, 175 | createdAt: Some(datetime), 176 | updatedAt: Some(datetime), 177 | }; 178 | 179 | vec.push(user_data.to_owned()); 180 | } 181 | 182 | let jwt_secret = data.env.jwt_secret.to_owned(); 183 | let now = Utc::now(); 184 | let iat = now.timestamp() as usize; 185 | let exp = (now + Duration::minutes(data.env.jwt_max_age)).timestamp() as usize; 186 | let claims: TokenClaims = TokenClaims { 187 | sub: user_id, 188 | exp, 189 | iat, 190 | }; 191 | 192 | let token = encode( 193 | &Header::default(), 194 | &claims, 195 | &EncodingKey::from_secret(jwt_secret.as_ref()), 196 | ) 197 | .unwrap(); 198 | 199 | let cookie = Cookie::build("token", token) 200 | .path("/") 201 | .max_age(ActixWebDuration::new(60 * data.env.jwt_max_age, 0)) 202 | .http_only(true) 203 | .finish(); 204 | 205 | let frontend_origin = data.env.client_origin.to_owned(); 206 | let mut response = HttpResponse::Found(); 207 | response.append_header((LOCATION, format!("{}{}", frontend_origin, state))); 208 | response.cookie(cookie); 209 | response.finish() 210 | } 211 | 212 | #[get("/sessions/oauth/github")] 213 | async fn github_oauth_handler( 214 | query: web::Query, 215 | data: web::Data, 216 | ) -> impl Responder { 217 | let code = &query.code; 218 | let state = &query.state; 219 | 220 | if code.is_empty() { 221 | return HttpResponse::Unauthorized().json( 222 | serde_json::json!({"status": "fail", "message": "Authorization code not provided!"}), 223 | ); 224 | } 225 | 226 | let token_response = get_github_oauth_token(code.as_str(), &data).await; 227 | if token_response.is_err() { 228 | let message = token_response.err().unwrap().to_string(); 229 | return HttpResponse::BadGateway() 230 | .json(serde_json::json!({"status": "fail", "message": message})); 231 | } 232 | 233 | let token_response = token_response.unwrap(); 234 | println!("Bearer {}", token_response.access_token); 235 | let github_user = get_github_user(&token_response.access_token).await; 236 | if github_user.is_err() { 237 | let message = github_user.err().unwrap().to_string(); 238 | return HttpResponse::BadGateway() 239 | .json(serde_json::json!({"status": "fail", "message": message})); 240 | } 241 | 242 | let github_user = github_user.unwrap(); 243 | 244 | let mut vec = data.db.lock().unwrap(); 245 | let email = github_user.email.to_lowercase(); 246 | let user = vec.iter_mut().find(|user| user.email == email); 247 | 248 | let user_id: String; 249 | 250 | if user.is_some() { 251 | let user = user.unwrap(); 252 | user_id = user.id.to_owned().unwrap(); 253 | user.email = email.to_owned(); 254 | user.photo = github_user.avatar_url; 255 | user.updatedAt = Some(Utc::now()); 256 | } else { 257 | let datetime = Utc::now(); 258 | let id = Uuid::new_v4(); 259 | user_id = id.to_owned().to_string(); 260 | let user_data = User { 261 | id: Some(id.to_string()), 262 | name: github_user.login, 263 | verified: true, 264 | email, 265 | provider: "GitHub".to_string(), 266 | role: "user".to_string(), 267 | password: "".to_string(), 268 | photo: github_user.avatar_url, 269 | createdAt: Some(datetime), 270 | updatedAt: Some(datetime), 271 | }; 272 | 273 | vec.push(user_data.to_owned()); 274 | } 275 | 276 | let jwt_secret = data.env.jwt_secret.to_owned(); 277 | let now = Utc::now(); 278 | let iat = now.timestamp() as usize; 279 | let exp = (now + Duration::minutes(data.env.jwt_max_age)).timestamp() as usize; 280 | let claims: TokenClaims = TokenClaims { 281 | sub: user_id, 282 | exp, 283 | iat, 284 | }; 285 | 286 | let token = encode( 287 | &Header::default(), 288 | &claims, 289 | &EncodingKey::from_secret(jwt_secret.as_ref()), 290 | ) 291 | .unwrap(); 292 | 293 | let cookie = Cookie::build("token", token) 294 | .path("/") 295 | .max_age(ActixWebDuration::new(60 * data.env.jwt_max_age, 0)) 296 | .http_only(true) 297 | .finish(); 298 | 299 | let frontend_origin = data.env.client_origin.to_owned(); 300 | let mut response = HttpResponse::Found(); 301 | response.append_header((LOCATION, format!("{}{}", frontend_origin, state))); 302 | response.cookie(cookie); 303 | response.finish() 304 | } 305 | 306 | #[get("/auth/logout")] 307 | async fn logout_handler(_: AuthenticationGuard) -> impl Responder { 308 | let cookie = Cookie::build("token", "") 309 | .path("/") 310 | .max_age(ActixWebDuration::new(-1, 0)) 311 | .http_only(true) 312 | .finish(); 313 | 314 | HttpResponse::Ok() 315 | .cookie(cookie) 316 | .json(serde_json::json!({"status": "success"})) 317 | } 318 | 319 | #[get("/users/me")] 320 | async fn get_me_handler( 321 | auth_guard: AuthenticationGuard, 322 | data: web::Data, 323 | ) -> impl Responder { 324 | let vec = data.db.lock().unwrap(); 325 | 326 | let user = vec 327 | .iter() 328 | .find(|user| user.id == Some(auth_guard.user_id.to_owned())); 329 | 330 | let json_response = UserResponse { 331 | status: "success".to_string(), 332 | data: UserData { 333 | user: user_to_response(&user.unwrap()), 334 | }, 335 | }; 336 | 337 | HttpResponse::Ok().json(json_response) 338 | } 339 | 340 | pub fn user_to_response(user: &User) -> FilteredUser { 341 | FilteredUser { 342 | id: user.id.to_owned().unwrap(), 343 | name: user.name.to_owned(), 344 | email: user.email.to_owned(), 345 | verified: user.verified.to_owned(), 346 | photo: user.photo.to_owned(), 347 | provider: user.provider.to_owned(), 348 | role: user.role.to_owned(), 349 | createdAt: user.createdAt.unwrap(), 350 | updatedAt: user.updatedAt.unwrap(), 351 | } 352 | } 353 | 354 | pub fn config(conf: &mut web::ServiceConfig) { 355 | let scope = web::scope("/api") 356 | .service(health_checker_handler) 357 | .service(register_user_handler) 358 | .service(login_user_handler) 359 | .service(google_oauth_handler) 360 | .service(github_oauth_handler) 361 | .service(logout_handler) 362 | .service(get_me_handler); 363 | 364 | conf.service(scope); 365 | } 366 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod authenticate_token; 2 | mod config; 3 | mod github_oauth; 4 | mod google_oauth; 5 | mod handler; 6 | mod model; 7 | mod response; 8 | 9 | use actix_cors::Cors; 10 | use actix_web::middleware::Logger; 11 | use actix_web::{http::header, web, App, HttpServer}; 12 | use dotenv::dotenv; 13 | use model::AppState; 14 | 15 | #[actix_web::main] 16 | async fn main() -> std::io::Result<()> { 17 | if std::env::var_os("RUST_LOG").is_none() { 18 | std::env::set_var("RUST_LOG", "actix_web=info"); 19 | } 20 | dotenv().ok(); 21 | env_logger::init(); 22 | 23 | let db = AppState::init(); 24 | let app_data = web::Data::new(db); 25 | let public_dir = std::env::current_dir().unwrap().join("public"); 26 | 27 | println!("🚀 Server started successfully"); 28 | 29 | HttpServer::new(move || { 30 | let cors = Cors::default() 31 | .allowed_origin("http://localhost:3000") 32 | .allowed_methods(vec!["GET", "POST"]) 33 | .allowed_headers(vec![ 34 | header::CONTENT_TYPE, 35 | header::AUTHORIZATION, 36 | header::ACCEPT, 37 | ]) 38 | .supports_credentials(); 39 | App::new() 40 | .app_data(app_data.clone()) 41 | .service(actix_files::Files::new("/api/images", &public_dir)) 42 | .configure(handler::config) 43 | .wrap(cors) 44 | .wrap(Logger::default()) 45 | }) 46 | .bind(("127.0.0.1", 8000))? 47 | .run() 48 | .await 49 | } 50 | -------------------------------------------------------------------------------- /src/model.rs: -------------------------------------------------------------------------------- 1 | use chrono::prelude::*; 2 | use serde::{Deserialize, Serialize}; 3 | use std::sync::{Arc, Mutex}; 4 | 5 | use crate::config; 6 | 7 | #[allow(non_snake_case)] 8 | #[derive(Debug, Deserialize, Serialize, Clone)] 9 | pub struct User { 10 | pub id: Option, 11 | pub name: String, 12 | pub email: String, 13 | pub password: String, 14 | pub role: String, 15 | pub photo: String, 16 | pub verified: bool, 17 | pub provider: String, 18 | pub createdAt: Option>, 19 | pub updatedAt: Option>, 20 | } 21 | 22 | pub struct AppState { 23 | pub db: Arc>>, 24 | pub env: config::Config, 25 | } 26 | 27 | impl AppState { 28 | pub fn init() -> AppState { 29 | AppState { 30 | db: Arc::new(Mutex::new(Vec::new())), 31 | env: config::Config::init(), 32 | } 33 | } 34 | } 35 | 36 | #[derive(Debug, Serialize, Deserialize)] 37 | pub struct TokenClaims { 38 | pub sub: String, 39 | pub iat: usize, 40 | pub exp: usize, 41 | } 42 | 43 | #[derive(Debug, Deserialize)] 44 | pub struct QueryCode { 45 | pub code: String, 46 | pub state: String, 47 | } 48 | 49 | #[derive(Debug, Deserialize)] 50 | pub struct RegisterUserSchema { 51 | pub name: String, 52 | pub email: String, 53 | pub password: String, 54 | } 55 | 56 | #[derive(Debug, Deserialize)] 57 | pub struct LoginUserSchema { 58 | pub email: String, 59 | pub password: String, 60 | } 61 | -------------------------------------------------------------------------------- /src/response.rs: -------------------------------------------------------------------------------- 1 | use chrono::prelude::*; 2 | use serde::Serialize; 3 | 4 | #[allow(non_snake_case)] 5 | #[derive(Debug, Serialize)] 6 | pub struct FilteredUser { 7 | pub id: String, 8 | pub name: String, 9 | pub email: String, 10 | pub role: String, 11 | pub photo: String, 12 | pub verified: bool, 13 | pub provider: String, 14 | pub createdAt: DateTime, 15 | pub updatedAt: DateTime, 16 | } 17 | 18 | #[derive(Serialize, Debug)] 19 | pub struct UserData { 20 | pub user: FilteredUser, 21 | } 22 | 23 | #[derive(Serialize, Debug)] 24 | pub struct UserResponse { 25 | pub status: String, 26 | pub data: UserData, 27 | } 28 | --------------------------------------------------------------------------------