commit ec73d6584ff3348705dc94ddb7bb563cc0deea7f Author: Roman Bessonov Date: Mon Jun 6 14:17:58 2022 +0500 init project, impl authorization diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..e0df003 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,3 @@ +/target +*.env +.idea/ \ No newline at end of file diff --git a/backend/Cargo.lock b/backend/Cargo.lock new file mode 100644 index 0000000..fe361b4 --- /dev/null +++ b/backend/Cargo.lock @@ -0,0 +1,1947 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "log", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "actix-http" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5885cb81a0d4d0d322864bea1bb6c2a8144626b4fdc625d4c51eba197e7797a" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64", + "bitflags", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha-1", + "smallvec", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "actix-router" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80" +dependencies = [ + "bytestring", + "firestorm", + "http", + "log", + "regex", + "serde", +] + +[[package]] +name = "actix-rt" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "num_cpus", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e5ebffd51d50df56a3ae0de0e59487340ca456f05dd0b90c0a7a6dd6a74d31" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time 0.3.9", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7525bedf54704abb1d469e88d7e7e9226df73778798a69cea5022d53b2ae91bc" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backend" +version = "0.1.0" +dependencies = [ + "actix-web", + "base64", + "chrono", + "derive_more", + "dotenv", + "futures", + "jsonwebtoken", + "mime", + "rand", + "rmp-serde", + "serde", + "sha2", + "sqlx", + "uuid 1.1.1", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "bytestring" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.43", + "winapi", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" +dependencies = [ + "percent-encoding", + "time 0.3.9", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + +[[package]] +name = "firestorm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98" + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.11.2", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9051c17f81bae79440afa041b3a278e1de71bfb96d32454b477fd4703ccb6f" +dependencies = [ + "base64", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "local-channel" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +dependencies = [ + "futures-core", + "futures-sink", + "futures-util", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "md-5" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +dependencies = [ + "digest", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "pem" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +dependencies = [ + "base64", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rmp" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25786b0d276110195fa3d6f3f31299900cf71dfbd6c28450f3f58a0e7f7a347e" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time 0.3.9", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "sqlformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" +dependencies = [ + "ahash", + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "dirs", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-util", + "hashlink", + "hex", + "hkdf", + "hmac", + "indexmap", + "itoa", + "libc", + "log", + "md-5", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "rand", + "rustls", + "serde", + "serde_json", + "sha-1", + "sha2", + "smallvec", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "tokio-stream", + "url", + "uuid 0.8.2", + "webpki", + "webpki-roots", + "whoami", +] + +[[package]] +name = "sqlx-macros" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" +dependencies = [ + "dotenv", + "either", + "heck", + "once_cell", + "proc-macro2", + "quote", + "sha2", + "sqlx-core", + "sqlx-rt", + "syn", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" +dependencies = [ + "actix-rt", + "once_cell", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot 0.12.0", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "winapi", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tracing" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "uuid" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6d5d669b51467dcf7b2f1a796ce0f955f05f01cafda6c19d6e95f730df29238" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + +[[package]] +name = "whoami" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "zstd" +version = "0.10.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "4.1.6+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +dependencies = [ + "cc", + "libc", +] diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 0000000..c47f488 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "backend" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = "4.0.1" +serde = "1.0.137" +rmp-serde = "1.1.0" +sqlx = { version = "0.5", features = ["runtime-actix-rustls", "postgres", "migrate", "uuid", "chrono"] } +dotenv = "0.15.0" +uuid = { version = "1.1.1", features = ["v4", "serde"] } +futures = "0.3.21" +derive_more = "0.99.17" +mime = "0.3.16" +rand = "0.8.5" +sha2 = "0.10.2" +chrono = "0.4.19" +jsonwebtoken = "8.1.0" +base64 = "0.13.0" diff --git a/backend/migrations/20220601131817_create_account.sql b/backend/migrations/20220601131817_create_account.sql new file mode 100644 index 0000000..007ca75 --- /dev/null +++ b/backend/migrations/20220601131817_create_account.sql @@ -0,0 +1,9 @@ +-- Add migration script here +CREATE TABLE account +( + id uuid primary key, + username varchar(128) unique not null, + password_hash bytea not null, + password_salt varchar(32) not null, + email text null +); \ No newline at end of file diff --git a/backend/migrations/20220604192644_auth_token.sql b/backend/migrations/20220604192644_auth_token.sql new file mode 100644 index 0000000..6328d74 --- /dev/null +++ b/backend/migrations/20220604192644_auth_token.sql @@ -0,0 +1,9 @@ +-- Add migration script here +CREATE TABLE refresh_token +( + id uuid not null, + user_id uuid not null, + time_created timestamp not null, + CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES account (id) ON DELETE CASCADE, + PRIMARY KEY (id, user_id) +); \ No newline at end of file diff --git a/backend/src/controller/auth_controller.rs b/backend/src/controller/auth_controller.rs new file mode 100644 index 0000000..8090283 --- /dev/null +++ b/backend/src/controller/auth_controller.rs @@ -0,0 +1,41 @@ +use crate::dto::account::{CreateAccount, Login, Tokens}; +use crate::error::AppError; +use crate::utils::extractor::msgpack::MsgPack; +use crate::AccountService; +use actix_web::{post, web, Scope}; + +pub mod dto {} + +#[post("/register")] +pub async fn create_account( + account: MsgPack, + account_service: web::Data, +) -> MsgPack { + MsgPack(account_service.create_account(account.0).await) +} + +#[post("/login")] +pub async fn login( + login: MsgPack, + account_service: web::Data, +) -> Result, AppError> { + account_service + .login(login.0) + .await + .map(|data| MsgPack(data)) +} + +#[post("/refresh")] +pub async fn refresh( + token: String, + account_service: web::Data, +) -> Result, AppError> { + account_service + .refresh_token(token) + .await + .map(|data| MsgPack(data)) +} + +pub fn auth_controller_builder() -> Scope { + web::scope("/auth").service(create_account) +} diff --git a/backend/src/controller/mod.rs b/backend/src/controller/mod.rs new file mode 100644 index 0000000..94f7aba --- /dev/null +++ b/backend/src/controller/mod.rs @@ -0,0 +1 @@ +pub mod auth_controller; diff --git a/backend/src/data/account/account.rs b/backend/src/data/account/account.rs new file mode 100644 index 0000000..a709d97 --- /dev/null +++ b/backend/src/data/account/account.rs @@ -0,0 +1,34 @@ +use crate::service::account::entity::Account as AccountEntity; +use crate::utils::uuid::{sqlx_uuid_to_uuid, uuid_to_sqlx_uuid}; + +pub struct Account { + pub id: sqlx::types::Uuid, + pub username: String, + pub password_hash: Vec, + pub password_salt: String, + pub email: Option, +} + +impl From for Account { + fn from(entity: AccountEntity) -> Self { + Account { + id: uuid_to_sqlx_uuid(entity.id), + username: entity.username, + password_hash: entity.password_hash, + password_salt: entity.password_salt, + email: entity.email, + } + } +} + +impl Into for Account { + fn into(self) -> AccountEntity { + AccountEntity::new( + sqlx_uuid_to_uuid(self.id), + self.username, + self.password_hash, + self.password_salt, + self.email, + ) + } +} diff --git a/backend/src/data/account/account_repository.rs b/backend/src/data/account/account_repository.rs new file mode 100644 index 0000000..d64163c --- /dev/null +++ b/backend/src/data/account/account_repository.rs @@ -0,0 +1,103 @@ +use crate::data::account::token::RefreshToken; +use crate::data::account::Account; +use crate::error::AppError; +use crate::service::account::entity::Account as AccountEntity; +use crate::utils::uuid::uuid_to_sqlx_uuid; +use sqlx::types::Uuid; +use sqlx::PgPool; + +#[derive(Clone)] +pub struct AccountRepository { + pool: PgPool, +} + +impl AccountRepository { + pub fn new(pool: PgPool) -> Self { + AccountRepository { pool } + } + + pub async fn create_account(&self, create_account: AccountEntity) -> AccountEntity { + let account: Account = create_account.into(); + sqlx::query_as!( + Account, + "INSERT INTO account(id, username, password_hash, password_salt, email) VALUES ($1, $2, $3, $4, $5) RETURNING *", + account.id, + account.username, + account.password_hash, + account.password_salt, + account.email, + ) + .fetch_one(&self.pool) + .await + .unwrap() + .into() + } + + pub async fn create_refresh_token(&self, for_account: uuid::Uuid) -> RefreshToken { + let id = Uuid::from_bytes(for_account.into_bytes()); + + sqlx::query_as!( + RefreshToken, + "INSERT INTO refresh_token(id, user_id, time_created) VALUES ($1, $2, $3) RETURNING *", + Uuid::from_bytes(uuid::Uuid::new_v4().into_bytes()), + id, + chrono::Utc::now().naive_utc(), + ) + .fetch_one(&self.pool) + .await + .unwrap() + } + + pub async fn get_account(&self, id: uuid::Uuid) -> Result, AppError> { + Ok(sqlx::query_as!( + Account, + "SELECT * FROM account WHERE id = $1", + uuid_to_sqlx_uuid(id), + ) + .fetch_optional(&self.pool) + .await? + .map(|account| account.into())) + } + + pub async fn get_account_by_name( + &self, + name: String, + ) -> Result, AppError> { + Ok( + sqlx::query_as!(Account, "SELECT * FROM account WHERE username = $1", name,) + .fetch_optional(&self.pool) + .await? + .map(|account| account.into()), + ) + } + + pub async fn get_refresh_token( + &self, + token_id: uuid::Uuid, + user_id: uuid::Uuid, + ) -> Result, AppError> { + Ok(sqlx::query_as!( + RefreshToken, + "SELECT * FROM refresh_token WHERE id = $1 AND user_id = $2", + uuid_to_sqlx_uuid(token_id), + uuid_to_sqlx_uuid(user_id), + ) + .fetch_optional(&self.pool) + .await?) + } + + pub async fn delete_refresh_token( + &self, + token_id: uuid::Uuid, + user_id: uuid::Uuid, + ) -> Result<(), AppError> { + sqlx::query!( + "DELETE FROM refresh_token WHERE id = $1 AND user_id = $2", + uuid_to_sqlx_uuid(token_id), + uuid_to_sqlx_uuid(user_id), + ) + .execute(&self.pool) + .await?; + Ok(()) + } +} diff --git a/backend/src/data/account/mod.rs b/backend/src/data/account/mod.rs new file mode 100644 index 0000000..01c5a37 --- /dev/null +++ b/backend/src/data/account/mod.rs @@ -0,0 +1,6 @@ +mod account; +mod account_repository; +mod token; + +pub use account::Account; +pub use account_repository::AccountRepository; diff --git a/backend/src/data/account/token.rs b/backend/src/data/account/token.rs new file mode 100644 index 0000000..907c643 --- /dev/null +++ b/backend/src/data/account/token.rs @@ -0,0 +1,7 @@ +use chrono::NaiveDateTime; + +pub struct RefreshToken { + pub id: sqlx::types::Uuid, + pub user_id: sqlx::types::Uuid, + pub time_created: NaiveDateTime, +} diff --git a/backend/src/data/mod.rs b/backend/src/data/mod.rs new file mode 100644 index 0000000..b0edc6c --- /dev/null +++ b/backend/src/data/mod.rs @@ -0,0 +1 @@ +pub mod account; diff --git a/backend/src/dto/account/mod.rs b/backend/src/dto/account/mod.rs new file mode 100644 index 0000000..c388920 --- /dev/null +++ b/backend/src/dto/account/mod.rs @@ -0,0 +1,57 @@ +use crate::service::account::entity::Account as AccountEntity; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Deserialize)] +pub struct CreateAccount { + pub name: String, + pub email: Option, + pub password: String, +} + +#[derive(Deserialize)] +pub struct Login { + pub name: String, + pub password: String, +} + +#[derive(Constructor, Serialize)] +pub struct Account { + pub email: Option, + pub name: String, + pub id: Uuid, +} + +#[derive(Constructor, Serialize)] +pub struct Tokens { + pub refresh: String, + pub access: String, +} + +#[derive(Constructor, Serialize)] +pub struct AccountCreated { + pub account: Account, + pub tokens: Tokens, +} + +#[derive(Constructor, Serialize, Deserialize)] +pub struct AccessTokenClaims { + pub exp: i64, + pub sub: String, + pub iat: i64, +} + +#[derive(Constructor, Serialize, Deserialize)] +pub struct RefreshTokenClaims { + pub exp: i64, + pub sub: String, + pub iat: i64, + pub refresh_token_id: Uuid, +} + +impl From for Account { + fn from(entity: AccountEntity) -> Self { + Account::new(entity.email, entity.username, entity.id) + } +} diff --git a/backend/src/dto/mod.rs b/backend/src/dto/mod.rs new file mode 100644 index 0000000..9fd0839 --- /dev/null +++ b/backend/src/dto/mod.rs @@ -0,0 +1,10 @@ +pub mod account; + +use derive_more::Constructor; +use serde::Serialize; + +#[derive(Serialize, Constructor)] +pub struct ErrorDto { + pub code: String, + pub message: Option, +} diff --git a/backend/src/error/mod.rs b/backend/src/error/mod.rs new file mode 100644 index 0000000..2cc490a --- /dev/null +++ b/backend/src/error/mod.rs @@ -0,0 +1,57 @@ +use crate::dto::ErrorDto; +use actix_web::body::BoxBody; +use actix_web::http::header::TryIntoHeaderValue; +use actix_web::http::StatusCode; +use actix_web::{HttpResponse, ResponseError}; +use derive_more::{Constructor, Display}; +use sqlx::Error; + +#[derive(Constructor, Display, Debug)] +#[display( + fmt = "AppError:status: {}, code: {}, message: {:?}", + status, + code, + message +)] +pub struct AppError { + code: String, + status: u16, + message: Option, +} + +impl AppError { + pub fn from_code(code: String) -> Self { + AppError::from_code_and_status(code, 400) + } + + pub fn from_code_and_status(code: String, status: u16) -> Self { + AppError::new(code, status, None) + } +} + +impl ResponseError for AppError { + fn status_code(&self) -> StatusCode { + StatusCode::from_u16(self.status).unwrap() + } + + fn error_response(&self) -> HttpResponse { + let mut response = HttpResponse::new(self.status_code()); + response.headers_mut().insert( + actix_web::http::header::CONTENT_TYPE, + mime::APPLICATION_MSGPACK.try_into_value().unwrap(), + ); + response.set_body(BoxBody::new( + rmp_serde::to_vec(&ErrorDto::new( + self.code.clone(), + self.message.as_ref().map(|data| data.clone()), + )) + .unwrap(), + )) + } +} + +impl From for AppError { + fn from(_: Error) -> Self { + AppError::from_code_and_status("INTERNAL_ERROR".to_string(), 500) + } +} diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..ab8c645 --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,46 @@ +mod controller; +mod data; +mod dto; +mod error; +mod service; +mod utils; + +use crate::controller::auth_controller::auth_controller_builder; +use crate::data::account::AccountRepository; +use crate::service::account::AccountService; +use crate::utils::env::extract_env_var; +use actix_web::{web, App, HttpServer}; +use sqlx::postgres::PgPoolOptions; + +const DB_URL_KEY: &str = "DATABASE_URL"; +const JWT_SECRET_KEY: &str = "JWT_SECRET"; + +#[derive(Clone)] +pub struct JwtSecretKey(Vec); + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + dotenv::dotenv().unwrap(); + + let db_url = extract_env_var(DB_URL_KEY); + let jwt_secret = extract_env_var(JWT_SECRET_KEY); + + let pool = PgPoolOptions::new().connect(db_url.as_str()).await.unwrap(); + sqlx::migrate!().run(&pool).await.unwrap(); + let key = JwtSecretKey(base64::decode(jwt_secret).unwrap()); + + let account_repository = AccountRepository::new(pool.clone()); + + HttpServer::new(move || { + App::new() + .service(auth_controller_builder()) + .app_data(web::Data::new(AccountService::new( + account_repository.clone(), + key.clone(), + ))) + .app_data(web::Data::new(key.clone())) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await +} diff --git a/backend/src/service/account/account_service.rs b/backend/src/service/account/account_service.rs new file mode 100644 index 0000000..25dc095 --- /dev/null +++ b/backend/src/service/account/account_service.rs @@ -0,0 +1,139 @@ +use crate::data::account::AccountRepository; +use crate::dto::account::{AccessTokenClaims, CreateAccount, Login, RefreshTokenClaims, Tokens}; +use crate::error::AppError; +use crate::service::account::entity::Account; +use crate::utils::uuid::sqlx_uuid_to_uuid; +use crate::JwtSecretKey; +use chrono::{Duration, Utc}; +use derive_more::Constructor; +use jsonwebtoken::errors::ErrorKind; +use jsonwebtoken::{decode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; +use rand::Rng; +use sha2::{Digest, Sha512}; +use std::ops::Add; +use uuid::Uuid; + +#[derive(Constructor, Clone)] +pub struct AccountService { + account_repository: AccountRepository, + secret: JwtSecretKey, +} + +impl AccountService { + pub async fn create_account(&self, create_account_dto: CreateAccount) -> Tokens { + let salt: String = rand::thread_rng() + .sample_iter::(rand::distributions::Standard) + .take(32) + .collect(); + let mut hasher = Sha512::new(); + hasher.update(create_account_dto.password.add(salt.as_str()).as_bytes()); + let hash = hasher.finalize().to_vec(); + let account = self + .account_repository + .create_account(Account::new( + Uuid::new_v4(), + create_account_dto.name, + hash, + salt, + create_account_dto.email, + )) + .await; + self.create_tokens(account.id).await + } + + pub async fn create_tokens(&self, for_account: Uuid) -> Tokens { + let header = Header::new(Algorithm::HS512); + let iat = Utc::now(); + let access_token_claims = AccessTokenClaims::new( + iat.add(Duration::hours(1)).timestamp(), + for_account.to_string(), + iat.timestamp(), + ); + let encoding_key = EncodingKey::from_secret(self.secret.0.as_slice()); + let access_token = + jsonwebtoken::encode(&header, &access_token_claims, &encoding_key).unwrap(); + let refresh_token_data = self + .account_repository + .create_refresh_token(for_account) + .await; + let refresh_token_claims = RefreshTokenClaims::new( + iat.add(Duration::days(30)).timestamp(), + refresh_token_data.user_id.to_string(), + iat.timestamp(), + sqlx_uuid_to_uuid(refresh_token_data.id), + ); + let refresh_token = + jsonwebtoken::encode(&header, &refresh_token_claims, &encoding_key).unwrap(); + Tokens::new(access_token, refresh_token) + } + + pub async fn login(&self, login_dto: Login) -> Result { + let account = if let Some(account) = self + .account_repository + .get_account_by_name(login_dto.name) + .await? + { + account + } else { + return Err(AppError::from_code("USER_NOT_FOUND".to_string())); + }; + let mut hasher = Sha512::new(); + hasher.update( + login_dto + .password + .add(account.password_salt.as_str()) + .as_bytes(), + ); + let hash = hasher.finalize().to_vec(); + if hash == account.password_hash { + Ok(self.create_tokens(account.id).await) + } else { + Err(AppError::from_code("INCORRECT_PASSWORD".to_string())) + } + } + + pub async fn refresh_token(&self, token: String) -> Result { + let token = match decode::( + token.as_str(), + &DecodingKey::from_secret(self.secret.0.as_slice()), + &Validation::new(Algorithm::HS512), + ) { + Err(err) => { + return Err(match *err.kind() { + ErrorKind::InvalidToken => { + AppError::from_code_and_status("NOT_TOKEN".to_string(), 400) + } + ErrorKind::ExpiredSignature => { + AppError::from_code_and_status("EXPIRED".to_string(), 403) + } + _ => AppError::from_code_and_status("INVALID_TOKEN".to_string(), 401), + }); + } + Ok(claims) => claims, + }; + let user_uuid = Uuid::parse_str(&token.claims.sub).unwrap(); + let token_uuid = token.claims.refresh_token_id; + let old_token = if let Some(token) = self + .account_repository + .get_refresh_token(token_uuid, user_uuid) + .await? + { + token + } else { + return Err(AppError::from_code_and_status( + "INVALID_TOKEN".to_string(), + 401, + )); + }; + if old_token.time_created.add(Duration::days(30)) > Utc::now().naive_utc() { + return Err(AppError::from_code_and_status( + "TOKEN_EXPIRED".to_string(), + 400, + )); + }; + self.account_repository + .delete_refresh_token(token_uuid, user_uuid) + .await?; + Ok(self.create_tokens(user_uuid).await) + } +} diff --git a/backend/src/service/account/entity/account.rs b/backend/src/service/account/entity/account.rs new file mode 100644 index 0000000..d83cbc0 --- /dev/null +++ b/backend/src/service/account/entity/account.rs @@ -0,0 +1,12 @@ +use derive_more::Constructor; +use serde::Serialize; +use uuid::Uuid; + +#[derive(Constructor, Serialize)] +pub struct Account { + pub id: Uuid, + pub username: String, + pub password_hash: Vec, + pub password_salt: String, + pub email: Option, +} diff --git a/backend/src/service/account/entity/mod.rs b/backend/src/service/account/entity/mod.rs new file mode 100644 index 0000000..1f669ae --- /dev/null +++ b/backend/src/service/account/entity/mod.rs @@ -0,0 +1,3 @@ +mod account; + +pub use account::Account; diff --git a/backend/src/service/account/mod.rs b/backend/src/service/account/mod.rs new file mode 100644 index 0000000..c27522b --- /dev/null +++ b/backend/src/service/account/mod.rs @@ -0,0 +1,4 @@ +mod account_service; +pub mod entity; + +pub use account_service::AccountService; diff --git a/backend/src/service/mod.rs b/backend/src/service/mod.rs new file mode 100644 index 0000000..b0edc6c --- /dev/null +++ b/backend/src/service/mod.rs @@ -0,0 +1 @@ +pub mod account; diff --git a/backend/src/utils/env.rs b/backend/src/utils/env.rs new file mode 100644 index 0000000..5dfdd19 --- /dev/null +++ b/backend/src/utils/env.rs @@ -0,0 +1,8 @@ +use std::env; + +pub fn extract_env_var(key: &str) -> String { + env::var(key).unwrap_or_else(|_| { + println!("Bruh, we need {} to be set", key); + std::process::exit(1) + }) +} diff --git a/backend/src/utils/extractor/mod.rs b/backend/src/utils/extractor/mod.rs new file mode 100644 index 0000000..3770b3c --- /dev/null +++ b/backend/src/utils/extractor/mod.rs @@ -0,0 +1 @@ +pub mod msgpack; diff --git a/backend/src/utils/extractor/msgpack.rs b/backend/src/utils/extractor/msgpack.rs new file mode 100644 index 0000000..9c5658f --- /dev/null +++ b/backend/src/utils/extractor/msgpack.rs @@ -0,0 +1,149 @@ +use actix_web::body::EitherBody; +use actix_web::dev::{Decompress, Payload}; +use actix_web::error::PayloadError; +use actix_web::http::StatusCode; +use actix_web::web::{Bytes, BytesMut}; +use actix_web::{Error, FromRequest, HttpRequest, HttpResponse, Responder, ResponseError}; +use derive_more::Display; +use futures::{ready, Stream}; +use rmp_serde::{decode::Error as RmpDecodeError, encode::Error as RmpEncodeError}; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::future::Future; +use std::marker::PhantomData; +use std::pin::Pin; +use std::task::Poll::{Pending, Ready}; +use std::task::{Context, Poll}; + +pub struct MsgPack(pub T); + +impl FromRequest for MsgPack { + type Error = Error; + type Future = MsgPackExtractFuture; + + fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { + MsgPackExtractFuture::new(req.clone(), payload) + } +} + +#[derive(Debug, Display)] +pub enum MsgPackError { + #[display(fmt = "Can not deserialize")] + Deserialize(RmpDecodeError), + #[display(fmt = "Reading payload error {}", _0)] + ReadPayload(PayloadError), + #[display(fmt = "Can not serialize msgpack")] + Serialize(RmpEncodeError), +} + +impl ResponseError for MsgPackError { + fn status_code(&self) -> StatusCode { + match self { + MsgPackError::Deserialize(_) => StatusCode::UNPROCESSABLE_ENTITY, + MsgPackError::ReadPayload(err) => err.status_code(), + MsgPackError::Serialize(_) => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + +pub struct MsgPackExtractFuture { + _req: HttpRequest, + fut: MsgPackBody, + _res: PhantomData, +} + +impl MsgPackExtractFuture { + fn new(req: HttpRequest, payload: &mut Payload) -> Self { + MsgPackExtractFuture { + _req: req.clone(), + fut: MsgPackBody::new(req.clone(), payload), + _res: PhantomData {}, + } + } +} + +impl Unpin for MsgPackExtractFuture {} + +impl Future for MsgPackExtractFuture { + type Output = Result, Error>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = self.get_mut(); + + let res = ready!(Pin::new(&mut this.fut).poll(cx)); + match res { + Ok(data) => Ready(Ok(MsgPack(data))), + Err(err) => Ready(Err(err.into())), + } + } +} + +struct MsgPackBody { + buf: BytesMut, + payload: Decompress, + _res: PhantomData, +} + +impl Unpin for MsgPackBody {} + +impl MsgPackBody { + fn new(req: HttpRequest, payload: &mut Payload) -> Self { + MsgPackBody { + payload: Decompress::from_headers(payload.take(), req.headers()), + buf: BytesMut::new(), + _res: PhantomData {}, + } + } +} + +impl Future for MsgPackBody { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = self.get_mut(); + + let next = ready!(Pin::new(&mut this.payload).poll_next(cx)); + match next { + None => { + let res = match rmp_serde::from_slice(&this.buf) { + Ok(data) => data, + Err(err) => { + return Ready(Err(MsgPackError::Deserialize(err))); + } + }; + Ready(Ok(res)) + } + Some(res) => { + let data: Bytes = match res { + Ok(data) => data, + Err(err) => { + return Ready(Err(MsgPackError::ReadPayload(err))); + } + }; + this.buf.extend_from_slice(&data); + Pending + } + } + } +} + +impl Responder for MsgPack { + type Body = EitherBody; + + fn respond_to(self, _: &HttpRequest) -> HttpResponse { + match rmp_serde::to_vec(&self.0) { + Ok(data) => { + match HttpResponse::Ok() + .content_type(mime::APPLICATION_MSGPACK) + .message_body(Bytes::from(data)) + { + Ok(response) => response.map_into_left_body(), + Err(err) => HttpResponse::from_error(err).map_into_right_body(), + } + } + Err(err) => { + HttpResponse::from_error(MsgPackError::Serialize(err)).map_into_right_body() + } + } + } +} diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs new file mode 100644 index 0000000..af25b17 --- /dev/null +++ b/backend/src/utils/mod.rs @@ -0,0 +1,3 @@ +pub mod env; +pub mod extractor; +pub mod uuid; diff --git a/backend/src/utils/uuid.rs b/backend/src/utils/uuid.rs new file mode 100644 index 0000000..920cb51 --- /dev/null +++ b/backend/src/utils/uuid.rs @@ -0,0 +1,7 @@ +pub fn sqlx_uuid_to_uuid(from: sqlx::types::Uuid) -> uuid::Uuid { + uuid::Uuid::from_bytes(*from.as_bytes()) +} + +pub fn uuid_to_sqlx_uuid(from: uuid::Uuid) -> sqlx::types::Uuid { + sqlx::types::Uuid::from_bytes(from.into_bytes()) +}