feat(api): fully implemented the register endpoint

This commit is contained in:
antifallobst 2023-08-17 00:24:29 +02:00
parent 2f2aa0e4a3
commit b794574850
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
8 changed files with 739 additions and 23 deletions

549
Cargo.lock generated
View File

@ -55,7 +55,7 @@ dependencies = [
"tokio",
"tokio-util",
"tracing",
"zstd",
"zstd 0.12.4",
]
[[package]]
@ -213,6 +213,17 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aes"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "ahash"
version = "0.7.6"
@ -336,6 +347,17 @@ version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
[[package]]
name = "async-trait"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.28",
]
[[package]]
name = "atoi"
version = "2.0.0"
@ -372,6 +394,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
[[package]]
name = "base64"
version = "0.21.2"
@ -478,6 +506,27 @@ dependencies = [
"bytes",
]
[[package]]
name = "bzip2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.82"
@ -518,6 +567,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "clang-sys"
version = "1.6.1"
@ -582,6 +641,12 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "convert_case"
version = "0.4.0"
@ -667,6 +732,12 @@ dependencies = [
"typenum",
]
[[package]]
name = "data-encoding"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "der"
version = "0.7.8"
@ -733,6 +804,18 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "enum-as-inner"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "env_logger"
version = "0.10.0"
@ -915,6 +998,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "gethostname"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
dependencies = [
"libc",
"windows-targets",
]
[[package]]
name = "getrandom"
version = "0.2.10"
@ -1045,6 +1138,17 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]]
name = "http"
version = "0.2.9"
@ -1097,6 +1201,17 @@ dependencies = [
"cc",
]
[[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 = "idna"
version = "0.4.0"
@ -1127,6 +1242,33 @@ dependencies = [
"hashbrown 0.14.0",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]]
name = "ipconfig"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
"socket2 0.5.3",
"widestring",
"windows-sys",
"winreg",
]
[[package]]
name = "ipnet"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "is-terminal"
version = "0.4.9"
@ -1275,6 +1417,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
@ -1315,6 +1463,85 @@ version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "mail-auth"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6b0969bac270a60560d3a6f89c812b3e39b2f4b3ca8d866063f482030d14f19"
dependencies = [
"ahash 0.8.3",
"flate2",
"lru-cache",
"mail-builder",
"mail-parser",
"parking_lot",
"quick-xml",
"ring",
"rustls-pemfile",
"serde",
"serde_json",
"trust-dns-resolver",
"zip",
]
[[package]]
name = "mail-builder"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765969f4385f88a62738e8ed63e2fa630571d7ed6fd96ca6932d699513dd8c28"
dependencies = [
"gethostname",
]
[[package]]
name = "mail-parser"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4158a1c18963244e083888b21465846dfb68d6170850ed1ab4742edd57c9d47"
dependencies = [
"encoding_rs",
]
[[package]]
name = "mail-send"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6d2b8d0cb56f199d36f527ff96453cf3b1cdfdacb5e4d154ac1d8fcd89873c2"
dependencies = [
"base64 0.20.0",
"gethostname",
"mail-auth",
"mail-builder",
"md5",
"rand",
"rustls 0.21.6",
"smtp-proto",
"tokio",
"tokio-rustls 0.24.1",
"webpki-roots 0.23.1",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "md-5"
version = "0.10.5"
@ -1324,6 +1551,12 @@ dependencies = [
"digest",
]
[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]]
name = "memchr"
version = "2.5.0"
@ -1375,7 +1608,8 @@ dependencies = [
"env_logger",
"libinjection",
"log",
"pbkdf2",
"mail-send",
"pbkdf2 0.12.2",
"serde",
"sha2",
"sqlx",
@ -1507,6 +1741,17 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "password-hash"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "password-hash"
version = "0.5.0"
@ -1524,6 +1769,18 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pbkdf2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
dependencies = [
"digest",
"hmac",
"password-hash 0.4.2",
"sha2",
]
[[package]]
name = "pbkdf2"
version = "0.12.2"
@ -1532,7 +1789,7 @@ checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
"password-hash",
"password-hash 0.5.0",
"sha2",
]
@ -1631,6 +1888,21 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quick-xml"
version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.32"
@ -1708,6 +1980,31 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
[[package]]
name = "resolv-conf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
dependencies = [
"hostname",
"quick-error",
]
[[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 0.5.2",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rsa"
version = "0.9.2"
@ -1764,6 +2061,59 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "rustls"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustls"
version = "0.21.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
dependencies = [
"log",
"ring",
"rustls-webpki 0.101.3",
"sct",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
dependencies = [
"base64 0.21.2",
]
[[package]]
name = "rustls-webpki"
version = "0.100.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.101.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.15"
@ -1776,6 +2126,16 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "semver"
version = "1.0.18"
@ -1887,6 +2247,12 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "smtp-proto"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b756ac662e92a0e5b360349bea5f0b0784d4be4541eff2972049dfdfd7f862"
[[package]]
name = "socket2"
version = "0.4.9"
@ -2312,6 +2678,27 @@ dependencies = [
"syn 2.0.28",
]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls 0.20.8",
"tokio",
"webpki",
]
[[package]]
name = "tokio-rustls"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls 0.21.6",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.14"
@ -2370,6 +2757,59 @@ dependencies = [
"once_cell",
]
[[package]]
name = "trust-dns-proto"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26"
dependencies = [
"async-trait",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"idna 0.2.3",
"ipnet",
"lazy_static",
"rand",
"ring",
"rustls 0.20.8",
"rustls-pemfile",
"smallvec",
"thiserror",
"tinyvec",
"tokio",
"tokio-rustls 0.23.4",
"tracing",
"url",
"webpki",
]
[[package]]
name = "trust-dns-resolver"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe"
dependencies = [
"cfg-if",
"futures-util",
"ipconfig",
"lazy_static",
"lru-cache",
"parking_lot",
"resolv-conf",
"rustls 0.20.8",
"smallvec",
"thiserror",
"tokio",
"tokio-rustls 0.23.4",
"tracing",
"trust-dns-proto",
"webpki-roots 0.22.6",
]
[[package]]
name = "typenum"
version = "1.16.0"
@ -2409,6 +2849,12 @@ 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.4.0"
@ -2416,7 +2862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
dependencies = [
"form_urlencoded",
"idna",
"idna 0.4.0",
"percent-encoding",
]
@ -2513,6 +2959,44 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
dependencies = [
"webpki",
]
[[package]]
name = "webpki-roots"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
dependencies = [
"rustls-webpki 0.100.1",
]
[[package]]
name = "which"
version = "4.4.0"
@ -2530,6 +3014,12 @@ version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"
[[package]]
name = "widestring"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
[[package]]
name = "winapi"
version = "0.3.9"
@ -2636,19 +3126,68 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys",
]
[[package]]
name = "zeroize"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
[[package]]
name = "zip"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
dependencies = [
"aes",
"byteorder",
"bzip2",
"constant_time_eq",
"crc32fast",
"crossbeam-utils",
"flate2",
"hmac",
"pbkdf2 0.11.0",
"sha1",
"time 0.3.25",
"zstd 0.11.2+zstd.1.5.2",
]
[[package]]
name = "zstd"
version = "0.11.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
dependencies = [
"zstd-safe 5.0.2+zstd.1.5.2",
]
[[package]]
name = "zstd"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
dependencies = [
"zstd-safe",
"zstd-safe 6.0.6",
]
[[package]]
name = "zstd-safe"
version = "5.0.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
dependencies = [
"libc",
"zstd-sys",
]
[[package]]

View File

@ -19,4 +19,5 @@ clap = { version = "4.3.21", features = ["derive"] }
actix-web-httpauth = "0.8.0"
sqlx = { version = "0.7.1", features = ["runtime-tokio", "mysql", "chrono"] }
uuid = { version = "1.4.1", features = ["v4"] }
chrono = "0.4"
chrono = "0.4"
mail-send = "0.4.0"

118
src/accounts.rs Normal file
View File

@ -0,0 +1,118 @@
use anyhow::{Error, Result};
use pbkdf2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Pbkdf2,
};
use sqlx::{mysql::MySqlPool, types::chrono as sqlx_chrono};
pub struct Account {
pub id: u64,
pub username: String,
pub email: String,
pub salt: String,
pub password: String,
pub joined: sqlx_chrono::NaiveDateTime,
pub verified: bool,
}
impl Account {
/// This doesn't check if an account with that name is already existing!
pub async fn new(
pool: &MySqlPool,
username: &String,
email: &String,
password: &String,
) -> Result<Self> {
let salt = SaltString::generate(&mut OsRng);
let hash = Pbkdf2
.hash_password(password.as_bytes(), &salt)
.map_err(|_| anyhow::Error::msg("Failed to hash the password"))?
.to_string();
let joined = sqlx_chrono::Utc::now().naive_utc();
sqlx::query!(
r#"INSERT INTO Accounts (username, email, salt, password, joined, verified) VALUES (?, ?, ?, ?, ?, false);"#,
username,
email,
salt.to_string(),
hash,
joined,
)
.execute(pool)
.await?;
match Account::from_username(pool, &username).await? {
Some(a) => Ok(a),
None => Err(Error::msg(
"The just created account can't be found in the database!",
)),
}
}
pub async fn from_username(pool: &MySqlPool, username: &String) -> Result<Option<Self>> {
match sqlx::query!(r#"SELECT * FROM Accounts WHERE username = ?;"#, username)
.fetch_one(pool)
.await
{
Ok(row) => {
let account = Account {
id: row.id,
username: row.username,
email: row.email,
salt: row.salt,
password: row.password,
joined: row.joined,
verified: row.verified != 0,
};
Ok(Some(account))
}
Err(sqlx::Error::RowNotFound) => Ok(None),
Err(e) => Err(Error::new(e)),
}
}
pub async fn from_id(pool: &MySqlPool, id: u64) -> Result<Option<Self>> {
match sqlx::query!(r#"SELECT * FROM Accounts WHERE id = ?;"#, id)
.fetch_one(pool)
.await
{
Ok(row) => {
let account = Account {
id: row.id,
username: row.username,
email: row.email,
salt: row.salt,
password: row.password,
joined: row.joined,
verified: row.verified != 0,
};
Ok(Some(account))
}
Err(sqlx::Error::RowNotFound) => Ok(None),
Err(e) => Err(Error::new(e)),
}
}
pub async fn from_email(pool: &MySqlPool, email: &String) -> Result<Option<Self>> {
match sqlx::query!(r#"SELECT * FROM Accounts WHERE email = ?;"#, email)
.fetch_one(pool)
.await
{
Ok(row) => {
let account = Account {
id: row.id,
username: row.username,
email: row.email,
salt: row.salt,
password: row.password,
joined: row.joined,
verified: row.verified != 0,
};
Ok(Some(account))
}
Err(sqlx::Error::RowNotFound) => Ok(None),
Err(e) => Err(Error::new(e)),
}
}
}

View File

@ -9,7 +9,7 @@ async fn register(
data: web::Data<ApiState>,
body: web::Json<data::RegisterRequest>,
) -> impl Responder {
match handlers::register(body.into_inner()).await {
match handlers::register(&data.pool, body.into_inner()).await {
Ok(resp) => match resp {
data::RegisterResponse::Success => HttpResponse::Ok().finish(),
data::RegisterResponse::Conflict(b) => HttpResponse::Conflict().json(web::Json(b)),
@ -25,7 +25,7 @@ async fn register(
#[post("/account/verify")]
async fn verify(data: web::Data<ApiState>, body: web::Json<data::VerifyRequest>) -> impl Responder {
match handlers::verify(body.into_inner()).await {
match handlers::verify(&data.pool, body.into_inner()).await {
Ok(resp) => match resp {
data::VerifyResponse::Success => HttpResponse::Ok().finish(),
data::VerifyResponse::TokenUnknown => HttpResponse::NotFound().finish(),
@ -43,7 +43,7 @@ async fn authenticate(
data: web::Data<ApiState>,
body: web::Json<data::AuthenticateRequest>,
) -> impl Responder {
match handlers::authenticate(body.into_inner()).await {
match handlers::authenticate(&data.pool, body.into_inner()).await {
Ok(resp) => match resp {
data::AuthenticateResponse::Success(b) => HttpResponse::Ok().json(web::Json(b)),
data::AuthenticateResponse::WrongPassword => HttpResponse::Unauthorized().finish(),
@ -59,7 +59,7 @@ async fn authenticate(
#[delete("/account/delete")]
async fn delete(data: web::Data<ApiState>, auth: BearerAuth) -> impl Responder {
match handlers::delete(auth.token().to_string()).await {
match handlers::delete(&data.pool, auth.token().to_string()).await {
Ok(resp) => match resp {
data::DeleteResponse::Success => HttpResponse::Ok().finish(),
data::DeleteResponse::Unauthorized => HttpResponse::Unauthorized().finish(),

View File

@ -1,6 +1,12 @@
use crate::api::account::data;
use crate::{
accounts::Account,
api::account::data,
tokens::{AuthToken, VerificationToken},
};
use anyhow::Result;
use log::info;
use mail_send::{mail_builder::MessageBuilder, SmtpClient, SmtpClientBuilder};
use sqlx::MySqlPool;
fn is_sql_injection(string: &String) -> bool {
match libinjection::sqli(string) {
@ -19,15 +25,55 @@ impl AlphaExt for String {
}
}
pub async fn register(request: data::RegisterRequest) -> Result<data::RegisterResponse> {
pub async fn register(
pool: &MySqlPool,
request: data::RegisterRequest,
) -> Result<data::RegisterResponse> {
if is_sql_injection(&request.username) || is_sql_injection(&request.email) {
return Ok(data::RegisterResponse::Blocked);
}
if Account::from_username(pool, &request.username).await?.is_some() {
return Ok(data::RegisterResponse::Conflict(
data::RegisterConflict::Username,
));
}
if Account::from_email(pool, &request.email).await?.is_some() {
return Ok(data::RegisterResponse::Conflict(
data::RegisterConflict::Email,
));
}
let account = Account::new(pool, &request.username, &request.email, &request.password).await?;
let token = VerificationToken::new(pool, account.id, chrono::Duration::minutes(10)).await?;
let message = MessageBuilder::new()
.from(("Nerdcult Account Management (noreply)", "account@nerdcult.net"))
.to(vec![
(request.username.as_str(), request.email.as_str()),
])
.subject("Account Verification")
.text_body(format!("Please verify your NerdCult account. Your code is {} (will be replaced with a link in future).", token.token));
SmtpClientBuilder::new(&std::env::var("SMTP_HOST_URL")?, 465)
.implicit_tls(true)
.credentials(mail_send::Credentials::Plain { username: &std::env::var("SMTP_USER")?, secret: &std::env::var("SMTP_PASSWORD")? })
.connect()
.await?
.send(message)
.await?;
info!("Verification Token: {:#?}", token);
Ok(data::RegisterResponse::Success)
}
pub async fn verify(request: data::VerifyRequest) -> Result<data::VerifyResponse> {
pub async fn verify(
pool: &MySqlPool,
request: data::VerifyRequest,
) -> Result<data::VerifyResponse> {
if !request.token.is_alpha() {
return Ok(data::VerifyResponse::Blocked);
}
@ -36,6 +82,7 @@ pub async fn verify(request: data::VerifyRequest) -> Result<data::VerifyResponse
}
pub async fn authenticate(
pool: &MySqlPool,
request: data::AuthenticateRequest,
) -> Result<data::AuthenticateResponse> {
if is_sql_injection(&request.username) {
@ -49,7 +96,7 @@ pub async fn authenticate(
))
}
pub async fn delete(token: String) -> Result<data::DeleteResponse> {
pub async fn delete(pool: &MySqlPool, token: String) -> Result<data::DeleteResponse> {
if !token.is_alpha() {
return Ok(data::DeleteResponse::Blocked);
}

View File

@ -15,7 +15,7 @@ pub async fn start(port: u16, pool: MySqlPool) -> Result<()> {
sqlx::query!(
r#"
CREATE TABLE IF NOT EXISTS Accounts (
id INT8 UNSIGNED NOT NULL AUTO_INCREMENT,
id INT8 UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
username VARCHAR(32) NOT NULL,
email TEXT NOT NULL,
salt VARCHAR(22) NOT NULL,

View File

@ -1,3 +1,4 @@
mod accounts;
mod api;
mod tokens;
@ -32,6 +33,16 @@ async fn main() -> Result<()> {
})?)
.await?;
let _ = &std::env::var("SMTP_HOST_URL").map_err(|_| {
anyhow::Error::msg("Environment variable SMTP_HOST_URL needs to be specified!")
})?;
let _ = &std::env::var("SMTP_USER").map_err(|_| {
anyhow::Error::msg("Environment variable SMTP_HOST_URL needs to be specified!")
})?;
let _ = &std::env::var("SMTP_PASSWORD").map_err(|_| {
anyhow::Error::msg("Environment variable SMTP_HOST_URL needs to be specified!")
})?;
api::start(port, pool).await?;
Ok(())

View File

@ -3,15 +3,15 @@ use sqlx::{mysql::MySqlPool, types::chrono as sqlx_chrono};
#[derive(Debug)]
pub struct AuthToken {
token: String,
account: u64,
expire: sqlx_chrono::NaiveDateTime,
pub token: String,
pub account: u64,
pub expire: sqlx_chrono::NaiveDateTime,
}
impl AuthToken {
pub async fn new(
pool: &MySqlPool,
account_id: usize,
account_id: u64,
lifetime: chrono::Duration,
) -> Result<Self> {
let expire = match sqlx_chrono::Utc::now()
@ -83,15 +83,15 @@ impl AuthToken {
#[derive(Debug)]
pub struct VerificationToken {
token: String,
account: u64,
expire: sqlx_chrono::NaiveDateTime,
pub token: String,
pub account: u64,
pub expire: sqlx_chrono::NaiveDateTime,
}
impl VerificationToken {
pub async fn new(
pool: &MySqlPool,
account_id: usize,
account_id: u64,
lifetime: chrono::Duration,
) -> Result<Self> {
let expire = match sqlx_chrono::Utc::now()