Many updates
Split codebase into modules Added custom all in one error type Added password to user model Added password hashing using bcrypt Added model validation for username using regex
This commit is contained in:
parent
409a28c170
commit
cb26393fcd
350
Cargo.lock
generated
350
Cargo.lock
generated
@ -45,22 +45,32 @@ dependencies = [
|
|||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"actix-web-httpauth",
|
"actix-web-httpauth",
|
||||||
|
"bcrypt",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
|
"comp",
|
||||||
|
"custom_error",
|
||||||
"diesel",
|
"diesel",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"futures",
|
"futures",
|
||||||
"json",
|
"json",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
|
"lazy-regex",
|
||||||
|
"lazy_static",
|
||||||
"listenfd",
|
"listenfd",
|
||||||
"log",
|
"log",
|
||||||
"nanoid",
|
"nanoid",
|
||||||
"r2d2",
|
"r2d2",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
|
"regex",
|
||||||
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"timeago",
|
||||||
"uuid 0.8.1",
|
"uuid 0.8.1",
|
||||||
"validator",
|
"validator",
|
||||||
|
"validator_derive",
|
||||||
"yarte",
|
"yarte",
|
||||||
"yarte_helpers",
|
"yarte_helpers",
|
||||||
]
|
]
|
||||||
@ -501,6 +511,25 @@ version = "0.11.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bcrypt"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f02d7d008a57bcb2251ba115b803934e02315edbde9a861c88713493e381b63"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.12.1",
|
||||||
|
"blowfish",
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"rand 0.7.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -551,6 +580,26 @@ dependencies = [
|
|||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-cipher-trait"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blowfish"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
||||||
|
dependencies = [
|
||||||
|
"block-cipher-trait",
|
||||||
|
"byteorder",
|
||||||
|
"opaque-debug",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli-sys"
|
name = "brotli-sys"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@ -627,6 +676,7 @@ checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -677,6 +727,12 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "comp"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7b6cae29f71a26f0dae0e291da438d6fced0e22e78aa1484cbbc085b5170949"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.10.3"
|
version = "0.10.3"
|
||||||
@ -735,6 +791,12 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "custom_error"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93a0fc65739ae998afc8d68e64bdac2efd1bc4ffa1a0703d171ef2defae3792f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -813,6 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "33d7ca63eb2efea87a7f56a283acc49e2ce4b2bd54adf7465dc1d81fef13d8fc"
|
checksum = "33d7ca63eb2efea87a7f56a283acc49e2ce4b2bd54adf7465dc1d81fef13d8fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
"diesel_derives",
|
"diesel_derives",
|
||||||
"libsqlite3-sys",
|
"libsqlite3-sys",
|
||||||
"r2d2",
|
"r2d2",
|
||||||
@ -1029,6 +1092,18 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-iterator"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-streaming-iterator"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@ -1179,6 +1254,15 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
@ -1198,9 +1282,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "377038bf3c89d18d6ca1431e7a5027194fbd724ca10592b9487ede5e8e144f42"
|
checksum = "79b7246d7e4b979c03fa093da39cfb3617a96bbeee6310af63991668d7e843ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@ -1287,6 +1371,12 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "if_chain"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -1317,6 +1407,16 @@ dependencies = [
|
|||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "isolang"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "265ef164908329e47e753c769b14cbb27434abf0c41984dca201484022f09ce5"
|
||||||
|
dependencies = [
|
||||||
|
"phf 0.7.24",
|
||||||
|
"phf_codegen 0.7.24",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
@ -1368,6 +1468,15 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "03d91276c62198fd9dd1be0d8a4ed647d0a51d5d6a0679dc324dd0b499d024ff"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -1402,6 +1511,7 @@ version = "0.17.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56d90181c2904c287e5390186be820e5ef311a3c62edebb7d6ca3d6a48ce041d"
|
checksum = "56d90181c2904c287e5390186be820e5ef311a3c62edebb7d6ca3d6a48ce041d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@ -1417,9 +1527,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
version = "0.5.2"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "listenfd"
|
name = "listenfd"
|
||||||
@ -1472,8 +1582,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab"
|
checksum = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"phf",
|
"phf 0.8.0",
|
||||||
"phf_codegen",
|
"phf_codegen 0.8.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -1672,6 +1782,12 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -1719,13 +1835,32 @@ version = "2.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.7.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared 0.7.24",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared",
|
"phf_shared 0.8.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_codegen"
|
||||||
|
version = "0.7.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator 0.7.24",
|
||||||
|
"phf_shared 0.7.24",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1734,8 +1869,18 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
|
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator",
|
"phf_generator 0.8.0",
|
||||||
"phf_shared",
|
"phf_shared 0.8.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.7.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared 0.7.24",
|
||||||
|
"rand 0.6.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1744,33 +1889,42 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared",
|
"phf_shared 0.8.0",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.7.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher 0.2.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
|
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher",
|
"siphasher 0.3.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "0.4.10"
|
version = "0.4.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36e3dcd42688c05a66f841d22c5d8390d9a5d4c9aaf57b9285eae4900a080063"
|
checksum = "82c3bfbfb5bb42f99498c7234bbd768c220eb0cea6818259d0d18a1aa3d2595d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-internal",
|
"pin-project-internal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-internal"
|
name = "pin-project-internal"
|
||||||
version = "0.4.10"
|
version = "0.4.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4d7346ac577ff1296e06a418e7618e22655bae834d4970cb6e39d6da8119969"
|
checksum = "ccbf6449dcfb18562c015526b085b8df1aa3cdab180af8ec2ebd300a3bd28f63"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12",
|
"proc-macro2 1.0.12",
|
||||||
"quote 1.0.4",
|
"quote 1.0.4",
|
||||||
@ -1779,9 +1933,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
|
checksum = "f7505eeebd78492e0f6108f7171c4948dbb120ee8119d9d77d0afa5469bef67f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
@ -1872,15 +2026,6 @@ dependencies = [
|
|||||||
"unicode-xid 0.2.0",
|
"unicode-xid 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2-impersonated"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d32df793782c132f437089d84b487d617a0baac886fa8519751dca07db9266e0"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-xid 0.2.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
@ -1905,15 +2050,6 @@ dependencies = [
|
|||||||
"proc-macro2 1.0.12",
|
"proc-macro2 1.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote-impersonated"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3e3e450e6f50c99055b77f01eb206d8accbb7a1d14c2c7be2b0a829286296dc9"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2-impersonated",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "r2d2"
|
name = "r2d2"
|
||||||
version = "0.8.8"
|
version = "0.8.8"
|
||||||
@ -2160,6 +2296,21 @@ dependencies = [
|
|||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusqlite"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64a656821bb6317a84b257737b7934f79c0dbb7eb694710475908280ebad3e64"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"fallible-iterator",
|
||||||
|
"fallible-streaming-iterator",
|
||||||
|
"libsqlite3-sys",
|
||||||
|
"lru-cache",
|
||||||
|
"memchr",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-argon2"
|
name = "rust-argon2"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -2311,6 +2462,12 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -2355,7 +2512,7 @@ checksum = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"phf_shared",
|
"phf_shared 0.8.0",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -2366,8 +2523,8 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
|
checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator",
|
"phf_generator 0.8.0",
|
||||||
"phf_shared",
|
"phf_shared 0.8.0",
|
||||||
"proc-macro2 1.0.12",
|
"proc-macro2 1.0.12",
|
||||||
"quote 1.0.4",
|
"quote 1.0.4",
|
||||||
]
|
]
|
||||||
@ -2386,26 +2543,15 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.18"
|
version = "1.0.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
|
checksum = "e8e5aa70697bb26ee62214ae3288465ecec0000f05182f039b477001f08f5ae7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.12",
|
"proc-macro2 1.0.12",
|
||||||
"quote 1.0.4",
|
"quote 1.0.4",
|
||||||
"unicode-xid 0.2.0",
|
"unicode-xid 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn-impersonated"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c11664eb1aded8a1be30656bedb3c2ee3d6b594842c90ec635cf7b855a5d8478"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2-impersonated",
|
|
||||||
"quote-impersonated",
|
|
||||||
"unicode-xid 0.2.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@ -2529,6 +2675,16 @@ dependencies = [
|
|||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "timeago"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aff2f3f1ac92d664adfdea85496dceb8c044f66d62e7d953a059023385967cfc"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"isolang",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
@ -2536,7 +2692,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1"
|
checksum = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"iovec",
|
"iovec",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -2639,6 +2794,12 @@ dependencies = [
|
|||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@ -2755,12 +2916,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "v_eval"
|
name = "v_eval"
|
||||||
version = "0.5.3"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a419cdda656c514fbb974d5634994278be348867645cb65bf21a9b0676b9c2"
|
checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"syn-impersonated",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2788,6 +2949,21 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "validator_derive"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e668e9cd05c5009b833833aa1147e5727b5396ea401f22dd1167618eed4a10c9"
|
||||||
|
dependencies = [
|
||||||
|
"if_chain",
|
||||||
|
"lazy_static",
|
||||||
|
"proc-macro2 1.0.12",
|
||||||
|
"quote 1.0.4",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
"validator",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -2796,9 +2972,9 @@ checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
@ -2988,9 +3164,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte"
|
name = "yarte"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "884cff3b02a11d026c493282e598a5c990b17fa22b91fb73aad2bfeee47f4f01"
|
checksum = "819b7b4da6e6b0192ef2f8da43ed7d79716737a57246aff58ba75611f8083b94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yarte_derive",
|
"yarte_derive",
|
||||||
"yarte_helpers",
|
"yarte_helpers",
|
||||||
@ -2998,13 +3174,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_codegen"
|
name = "yarte_codegen"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a64e8ba00f9d77cd05b665b3515251544c5b1f4885e7e3f7ffc54ea27f52eabc"
|
checksum = "e3c178dcde178349d41d3b6c85353614fa43c2ddceba3e86073a864454149165"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2-impersonated",
|
"proc-macro2 1.0.12",
|
||||||
"quote-impersonated",
|
"quote 1.0.4",
|
||||||
"syn-impersonated",
|
"syn",
|
||||||
"yarte_dom",
|
"yarte_dom",
|
||||||
"yarte_helpers",
|
"yarte_helpers",
|
||||||
"yarte_hir",
|
"yarte_hir",
|
||||||
@ -3013,14 +3189,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_derive"
|
name = "yarte_derive"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50f11ebd841875bd9b906017844640aaac1571a4a188b3f7577efd6c02616da1"
|
checksum = "3a549fd6831f6354c39bb83bf78d7587e9b5ff18f7d390aefc4ba89435ba114f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prettyprint",
|
"prettyprint",
|
||||||
"proc-macro2-impersonated",
|
"proc-macro2 1.0.12",
|
||||||
"quote-impersonated",
|
"quote 1.0.4",
|
||||||
"syn-impersonated",
|
"syn",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"toolchain_find",
|
"toolchain_find",
|
||||||
"yarte_codegen",
|
"yarte_codegen",
|
||||||
@ -3031,13 +3207,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_dom"
|
name = "yarte_dom"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43cc56a6351af550001f7f7e07be3581cde4908a8ddcbba34630168afc4ebabc"
|
checksum = "c08abf1e4cbf721cce79c77a7da1e42b37e7321966724b094891dc0c3d1d5cda"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
"quote-impersonated",
|
"quote 1.0.4",
|
||||||
"syn-impersonated",
|
"syn",
|
||||||
"yarte_helpers",
|
"yarte_helpers",
|
||||||
"yarte_hir",
|
"yarte_hir",
|
||||||
"yarte_html",
|
"yarte_html",
|
||||||
@ -3045,9 +3221,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_helpers"
|
name = "yarte_helpers"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "771250e834a31e39a6e34e48e3fd9032542d211cb3f194f9a71b603fb841a793"
|
checksum = "e981464e47692f747fbc3f29cf271f65ac363cde5518ae77a50617d5490b9fce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml",
|
||||||
@ -3056,14 +3232,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_hir"
|
name = "yarte_hir"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c86bad7da0c2ae56374390919fa1d7abaa067f6325a3e27865ae8598bfc24057"
|
checksum = "6105dad390184a8e4afdce19cdd0956ae1af057da1571d7add988527cbd59953"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"proc-macro2-impersonated",
|
"proc-macro2 1.0.12",
|
||||||
"quote-impersonated",
|
"quote 1.0.4",
|
||||||
"syn-impersonated",
|
"syn",
|
||||||
"v_eval",
|
"v_eval",
|
||||||
"v_htmlescape",
|
"v_htmlescape",
|
||||||
"yarte_helpers",
|
"yarte_helpers",
|
||||||
@ -3072,9 +3248,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_html"
|
name = "yarte_html"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "261043d486d9ecdcb33c68d0323444db6ab6915f90e973c5cbd4331560ec0281"
|
checksum = "a0e8c01747147af821238b33c76c3045420a245fcfb3e2987becf2860b54598a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"mac",
|
"mac",
|
||||||
@ -3087,15 +3263,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarte_parser"
|
name = "yarte_parser"
|
||||||
version = "0.8.3"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f855c622d29c8a8af4f4b7a3f81e83ac0be6e6074977a017c3945db05fba311"
|
checksum = "061ed8ddf990b97d89827c42346f1273d434e79a3618786d3f595f2f1befe418"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"annotate-snippets",
|
"annotate-snippets",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"proc-macro2-impersonated",
|
"proc-macro2 1.0.12",
|
||||||
"quote-impersonated",
|
"quote 1.0.4",
|
||||||
"syn-impersonated",
|
"syn",
|
||||||
"unicode-xid 0.2.0",
|
"unicode-xid 0.2.0",
|
||||||
"yarte_helpers",
|
"yarte_helpers",
|
||||||
]
|
]
|
||||||
|
91
Cargo.toml
91
Cargo.toml
@ -1,43 +1,70 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-demo"
|
name = 'actix-demo'
|
||||||
version = "0.1.0"
|
version = '0.1.0'
|
||||||
authors = ["Rohan Sircar <rohansircar@tuta.io>"]
|
authors = ['Rohan Sircar <rohansircar@tuta.io>']
|
||||||
edition = "2018"
|
edition = '2018'
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "2"
|
actix-web = '2'
|
||||||
actix-rt = "1"
|
actix-rt = '1'
|
||||||
actix-service = "1.0.5"
|
actix-service = '1.0.5'
|
||||||
actix-files = "0.2.1"
|
actix-files = '0.2.1'
|
||||||
|
bytes = '0.5.4'
|
||||||
|
futures = '0.3.4'
|
||||||
|
log = '0.4.8'
|
||||||
|
env_logger = '0.7'
|
||||||
|
serde_json = '1.0.52'
|
||||||
|
json = '0.12.4'
|
||||||
|
listenfd = '0.3.3'
|
||||||
|
dotenv = '0.15'
|
||||||
|
r2d2 = '0.8.8'
|
||||||
|
validator = '0.10.0'
|
||||||
|
validator_derive = '0.10'
|
||||||
|
jsonwebtoken = '7'
|
||||||
|
actix-identity = '0.2.1'
|
||||||
|
actix-web-httpauth = '0.4.1'
|
||||||
|
actix-http = '1.0.1'
|
||||||
|
rand = '0.7.3'
|
||||||
|
nanoid = '0.3.0'
|
||||||
|
bcrypt = '0.7'
|
||||||
|
timeago = '0.2.1'
|
||||||
|
comp = '0.2.1'
|
||||||
|
regex = '1.3.7'
|
||||||
|
lazy_static = '1.4.0'
|
||||||
|
lazy-regex = '0.1.2'
|
||||||
|
custom_error = '1.7.1'
|
||||||
|
|
||||||
bytes = "0.5.4"
|
[dependencies.serde]
|
||||||
futures = "0.3.4"
|
version = '1.0.106'
|
||||||
log = "0.4.8"
|
features = ['derive']
|
||||||
env_logger = "0.7"
|
|
||||||
|
|
||||||
serde = { version = "1.0.106", features = ["derive"] }
|
[dependencies.yarte]
|
||||||
serde_json = "1.0.52"
|
version = '0.9.0'
|
||||||
json = "0.12.4"
|
features = ['html-min']
|
||||||
|
|
||||||
yarte = { version = "0.8.3", features = ["html-min"] }
|
[dependencies.diesel]
|
||||||
|
version = '1.4.4'
|
||||||
|
features = [
|
||||||
|
'sqlite',
|
||||||
|
'r2d2',
|
||||||
|
'chrono',
|
||||||
|
]
|
||||||
|
|
||||||
listenfd = "0.3.3"
|
[dependencies.uuid]
|
||||||
|
version = '0.8'
|
||||||
|
features = [
|
||||||
|
'serde',
|
||||||
|
'v4',
|
||||||
|
]
|
||||||
|
|
||||||
diesel = { version = "1.4.4", features = ["sqlite", "r2d2"] }
|
[dependencies.rusqlite]
|
||||||
dotenv = "0.15"
|
version = '0.21.0'
|
||||||
r2d2 = "0.8.8"
|
features = ['bundled']
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
|
||||||
validator = "0.10.0"
|
|
||||||
jsonwebtoken = "7"
|
|
||||||
actix-identity = "0.2.1"
|
|
||||||
actix-web-httpauth = "0.4.1"
|
|
||||||
actix-http = "1.0.1"
|
|
||||||
rand = "0.7.3"
|
|
||||||
nanoid = "0.3.0"
|
|
||||||
|
|
||||||
|
[dependencies.chrono]
|
||||||
|
version = '0.4.11'
|
||||||
|
features = ['serde']
|
||||||
[build-dependencies.yarte_helpers]
|
[build-dependencies.yarte_helpers]
|
||||||
version = "0.8"
|
version = '0.9.0'
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["config"]
|
features = ['config']
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
Testing out the Rust framework Actix-Web to create a JSON API CRUD Web App.
|
@ -1,5 +1,7 @@
|
|||||||
-- Your SQL goes here
|
-- Your SQL goes here
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
id INTEGER PRIMARY KEY NOT NULL ,
|
||||||
name VARCHAR NOT NULL
|
name VARCHAR NOT NULL,
|
||||||
|
password VARCHAR NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
|
@ -1,67 +1,2 @@
|
|||||||
use diesel::prelude::*;
|
pub mod users;
|
||||||
|
pub use self::users::*;
|
||||||
use crate::models;
|
|
||||||
|
|
||||||
pub fn find_user_by_uid(
|
|
||||||
uid: i32,
|
|
||||||
conn: &SqliteConnection,
|
|
||||||
) -> Result<Option<models::User>, diesel::result::Error> {
|
|
||||||
use crate::schema::users::dsl::*;
|
|
||||||
|
|
||||||
let maybe_user = users.find(uid).first::<models::User>(conn).optional();
|
|
||||||
|
|
||||||
// Ok(user)
|
|
||||||
maybe_user
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_user_by_name(
|
|
||||||
user_name: String,
|
|
||||||
conn: &SqliteConnection,
|
|
||||||
) -> Result<Option<models::User>, diesel::result::Error> {
|
|
||||||
use crate::schema::users::dsl::*;
|
|
||||||
|
|
||||||
let maybe_user = users
|
|
||||||
.filter(name.eq(user_name))
|
|
||||||
.first::<models::User>(conn)
|
|
||||||
.optional();
|
|
||||||
|
|
||||||
maybe_user
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_all(
|
|
||||||
conn: &SqliteConnection,
|
|
||||||
) -> Result<Option<Vec<models::User>>, diesel::result::Error> {
|
|
||||||
use crate::schema::users::dsl::*;
|
|
||||||
users.load::<models::User>(conn).optional()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run query using Diesel to insert a new database row and return the result.
|
|
||||||
pub fn insert_new_user(
|
|
||||||
nu: &models::NewUser,
|
|
||||||
conn: &SqliteConnection,
|
|
||||||
) -> Result<models::User, diesel::result::Error> {
|
|
||||||
// It is common when using Diesel with Actix web to import schema-related
|
|
||||||
// modules inside a function's scope (rather than the normal module's scope)
|
|
||||||
// to prevent import collisions and namespace pollution.
|
|
||||||
use crate::schema::users::dsl::*;
|
|
||||||
|
|
||||||
// let new_user = models::User {
|
|
||||||
// id: Uuid::new_v4().to_string(),
|
|
||||||
// name: nu.name.to_string(),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let x = users.load::<models::User>(conn).optional();
|
|
||||||
// let target = users.find("4");
|
|
||||||
// let test_user = models::User {
|
|
||||||
// id: "5".to_owned(),
|
|
||||||
// name: "who".to_owned(),
|
|
||||||
// };
|
|
||||||
// let update_result = diesel::update(target).set(&test_user).execute(conn);
|
|
||||||
|
|
||||||
diesel::insert_into(users).values(nu).execute(conn)?;
|
|
||||||
let user = users
|
|
||||||
.filter(name.eq(nu.name.clone()))
|
|
||||||
.first::<models::User>(conn);
|
|
||||||
user
|
|
||||||
// Ok(nu.clone())
|
|
||||||
}
|
|
||||||
|
83
src/actions/users.rs
Normal file
83
src/actions/users.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
use crate::models;
|
||||||
|
use bcrypt::{hash, DEFAULT_COST};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub fn find_user_by_uid(
|
||||||
|
uid: i32,
|
||||||
|
conn: &SqliteConnection,
|
||||||
|
) -> Result<Option<models::UserDTO>, errors::DomainError> {
|
||||||
|
use crate::schema::users::dsl::*;
|
||||||
|
|
||||||
|
let maybe_user = users
|
||||||
|
.select((name, created_at))
|
||||||
|
.find(uid)
|
||||||
|
.first::<models::UserDTO>(conn)
|
||||||
|
.optional();
|
||||||
|
|
||||||
|
Ok(maybe_user?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _find_user_by_name(
|
||||||
|
user_name: String,
|
||||||
|
conn: &SqliteConnection,
|
||||||
|
) -> Result<Option<models::UserDTO>, errors::DomainError> {
|
||||||
|
use crate::schema::users::dsl::*;
|
||||||
|
|
||||||
|
let maybe_user = users
|
||||||
|
.select((name, created_at))
|
||||||
|
.filter(name.eq(user_name))
|
||||||
|
.first::<models::UserDTO>(conn)
|
||||||
|
.optional();
|
||||||
|
|
||||||
|
Ok(maybe_user?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_all(
|
||||||
|
conn: &SqliteConnection,
|
||||||
|
) -> Result<Option<Vec<models::UserDTO>>, errors::DomainError> {
|
||||||
|
use crate::schema::users::dsl::*;
|
||||||
|
Ok(users
|
||||||
|
.select((name, created_at))
|
||||||
|
.load::<models::UserDTO>(conn)
|
||||||
|
.optional()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run query using Diesel to insert a new database row and return the result.
|
||||||
|
pub fn insert_new_user(
|
||||||
|
mut nu: Rc<models::NewUser>,
|
||||||
|
conn: &SqliteConnection,
|
||||||
|
) -> Result<models::UserDTO, errors::DomainError> {
|
||||||
|
// It is common when using Diesel with Actix web to import schema-related
|
||||||
|
// modules inside a function's scope (rather than the normal module's scope)
|
||||||
|
// to prevent import collisions and namespace pollution.
|
||||||
|
use crate::schema::users::dsl::*;
|
||||||
|
|
||||||
|
// let new_user = models::User {
|
||||||
|
// id: Uuid::new_v4().to_string(),
|
||||||
|
// name: nu.name.to_string(),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let x = users.load::<models::User>(conn).optional();
|
||||||
|
// let target = users.find("4");
|
||||||
|
// let test_user = models::User {
|
||||||
|
// id: "5".to_owned(),
|
||||||
|
// name: "who".to_owned(),
|
||||||
|
// };
|
||||||
|
// let update_result = diesel::update(target).set(&test_user).execute(conn);
|
||||||
|
|
||||||
|
// let mut nu2 = nu.clone();
|
||||||
|
let mut nu2 = Rc::make_mut(&mut nu);
|
||||||
|
nu2.password = hash(nu2.password.clone(), DEFAULT_COST)?;
|
||||||
|
|
||||||
|
diesel::insert_into(users)
|
||||||
|
.values(nu.as_ref())
|
||||||
|
.execute(conn)?;
|
||||||
|
let user = users
|
||||||
|
.select((name, created_at))
|
||||||
|
.filter(name.eq(nu.name.clone()))
|
||||||
|
.first::<models::UserDTO>(conn);
|
||||||
|
Ok(user?)
|
||||||
|
}
|
2
src/errors.rs
Normal file
2
src/errors.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod domain_error;
|
||||||
|
pub use self::domain_error::*;
|
88
src/errors/domain_error.rs
Normal file
88
src/errors/domain_error.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use actix_web::{HttpResponse, ResponseError};
|
||||||
|
use bcrypt::BcryptError;
|
||||||
|
use custom_error::custom_error;
|
||||||
|
// use derive_more::Display;
|
||||||
|
// use diesel::result::DatabaseErrorKind;
|
||||||
|
use crate::models::errors::*;
|
||||||
|
use r2d2;
|
||||||
|
use std::convert::From;
|
||||||
|
// use std::error::Error;
|
||||||
|
|
||||||
|
// pub enum DomainError {
|
||||||
|
// #[display(fmt = "PasswordHashError")]
|
||||||
|
// PwdHashError,
|
||||||
|
// #[display(fmt = "Bad Id")]
|
||||||
|
// IdError,
|
||||||
|
// #[display(fmt = "Generic Error")]
|
||||||
|
// GenericError,
|
||||||
|
// DuplicateValue,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl Error for DomainError {
|
||||||
|
// fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
|
// // Generic error, underlying cause isn't tracked.
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl From<DBError> for DomainError {
|
||||||
|
// fn from(error: DBError) -> DomainError {
|
||||||
|
// // We only care about UniqueViolations
|
||||||
|
// match error {
|
||||||
|
// DBError::DatabaseError(kind, info) => {
|
||||||
|
// let message = info.details().unwrap_or_else(|| info.message()).to_string();
|
||||||
|
// match kind {
|
||||||
|
// DatabaseErrorKind::UniqueViolation => DomainError::DuplicateValue(message),
|
||||||
|
// _ => DomainError::GenericError(message),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// _ => DomainError::GenericError(String::from("Some database error occured")),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
custom_error! { pub DomainError
|
||||||
|
PwdHashError {source: BcryptError} = "Failed to has password",
|
||||||
|
DbError {source: diesel::result::Error} = "Database error",
|
||||||
|
DbPoolError {source: r2d2::Error} = "Failed to get connection from pool",
|
||||||
|
GenericError {cause: String} = "Generic Error - Reason: {cause}"
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResponseError for DomainError {
|
||||||
|
fn error_response(&self) -> HttpResponse {
|
||||||
|
match self {
|
||||||
|
DomainError::PwdHashError { source } => {
|
||||||
|
HttpResponse::InternalServerError().json(ErrorModel {
|
||||||
|
status_code: 500,
|
||||||
|
reason: format!(
|
||||||
|
"{} {}",
|
||||||
|
"Unexpected Error - Failed to hash password", source
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
DomainError::DbError { source } => {
|
||||||
|
HttpResponse::InternalServerError().json(ErrorModel {
|
||||||
|
status_code: 500,
|
||||||
|
reason: format!("{} {}", "Unexpected Database Error", source),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
DomainError::DbPoolError { source } => {
|
||||||
|
HttpResponse::InternalServerError().json(ErrorModel {
|
||||||
|
status_code: 500,
|
||||||
|
reason: format!(
|
||||||
|
"{} {}",
|
||||||
|
"Unexpected Error - Failed to get connection from pool", source
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
DomainError::GenericError { cause } => HttpResponse::BadRequest().json(ErrorModel {
|
||||||
|
status_code: 400,
|
||||||
|
reason: format!(
|
||||||
|
"{} {}, ",
|
||||||
|
"Unexpected Database Error - ".to_owned(),
|
||||||
|
cause.clone()
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
188
src/main.rs
188
src/main.rs
@ -1,32 +1,43 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate diesel;
|
extern crate diesel;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate comp;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate validator_derive;
|
||||||
|
extern crate bcrypt;
|
||||||
|
extern crate custom_error;
|
||||||
|
extern crate regex;
|
||||||
|
extern crate validator;
|
||||||
|
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::ServiceRequest, error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse,
|
error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder,
|
||||||
HttpServer, Responder,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use yarte::Template;
|
use yarte::Template;
|
||||||
|
|
||||||
use actix_web_httpauth::{extractors::basic::BasicAuth, middleware::HttpAuthentication};
|
use actix_web_httpauth::middleware::HttpAuthentication;
|
||||||
|
|
||||||
use actix_http::cookie::SameSite;
|
use actix_http::cookie::SameSite;
|
||||||
use actix_identity::{CookieIdentityPolicy, Identity, IdentityService};
|
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
// use actix_http::*;
|
|
||||||
|
|
||||||
use actix_files as fs;
|
use actix_files as fs;
|
||||||
|
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::r2d2::{self, ConnectionManager};
|
use diesel::r2d2::{self, ConnectionManager};
|
||||||
use routes::*;
|
// use middlewares::csrf;
|
||||||
|
// use routes;
|
||||||
|
// use routes::users;
|
||||||
|
// use utils;
|
||||||
|
|
||||||
mod actions;
|
mod actions;
|
||||||
|
mod errors;
|
||||||
|
mod middlewares;
|
||||||
mod models;
|
mod models;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
@ -68,161 +79,14 @@ impl UserServiceImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserService {
|
|
||||||
fn do_something(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserService for UserServiceImpl {
|
|
||||||
fn do_something(&self) {
|
|
||||||
println!("hello");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fun1(user_service: &dyn UserService) {
|
|
||||||
user_service.do_something();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fun2<T>(user_service: T)
|
|
||||||
where
|
|
||||||
T: UserService,
|
|
||||||
{
|
|
||||||
user_service.do_something();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// In this example validator returns immediately,
|
|
||||||
/// but since it is required to return anything
|
|
||||||
/// that implements `IntoFuture` trait,
|
|
||||||
/// it can be extended to query database
|
|
||||||
/// or to do something else in a async manner.
|
|
||||||
async fn validator(req: ServiceRequest, credentials: BasicAuth) -> Result<ServiceRequest, Error> {
|
|
||||||
// All users are great and more than welcome!
|
|
||||||
// let pool = req.app_data::<DbPool>();
|
|
||||||
// let maybe_header = req.headers().get("Authorization");
|
|
||||||
// match maybe_header {
|
|
||||||
// Some(value) => {
|
|
||||||
// info!("{:?}", *value);
|
|
||||||
// let x: Result<Basic, _> = Scheme::parse(value);
|
|
||||||
// let y = x.expect("Error parsing header");
|
|
||||||
// println!("{}", y.user_id());
|
|
||||||
// println!("{:?}", y.password().clone());
|
|
||||||
// }
|
|
||||||
// None => debug!("Header not found"),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// maybe_header
|
|
||||||
// .map(|value| {
|
|
||||||
// let x: Result<Basic, _> = Scheme::parse(value);
|
|
||||||
// x
|
|
||||||
// })
|
|
||||||
// .map(|maybe_basic| {
|
|
||||||
// maybe_basic
|
|
||||||
// .map(|x| {
|
|
||||||
// println!("{}", x.user_id());
|
|
||||||
// println!("{:?}", x.password().clone());
|
|
||||||
// })
|
|
||||||
// .map_err(|x| println!("error parsing reason - {}", x.to_string()))
|
|
||||||
// // maybe_basic
|
|
||||||
// });
|
|
||||||
// let auth = Authorization::<Basic>;
|
|
||||||
println!("{}", credentials.user_id());
|
|
||||||
println!("{:?}", credentials.password());
|
|
||||||
Ok(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn parse(header: &HeaderValue) -> Result<Basic, ParseError> {
|
|
||||||
// // "Basic *" length
|
|
||||||
// if header.len() < 7 {
|
|
||||||
// return Err(ParseError::Invalid);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let mut parts = header.to_str()?.splitn(2, ' ');
|
|
||||||
// match parts.next() {
|
|
||||||
// Some(scheme) if scheme == "Basic" => (),
|
|
||||||
// _ => return Err(ParseError::MissingScheme),
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let decoded = base64::decode(parts.next().ok_or(ParseError::Invalid)?)?;
|
|
||||||
// let mut credentials = str::from_utf8(&decoded)?.splitn(2, ':');
|
|
||||||
|
|
||||||
// let user_id = credentials
|
|
||||||
// .next()
|
|
||||||
// .ok_or(ParseError::MissingField("user_id"))
|
|
||||||
// .map(|user_id| user_id.to_string().into())?;
|
|
||||||
// let password = credentials
|
|
||||||
// .next()
|
|
||||||
// .ok_or(ParseError::MissingField("password"))
|
|
||||||
// .map(|password| {
|
|
||||||
// if password.is_empty() {
|
|
||||||
// None
|
|
||||||
// } else {
|
|
||||||
// Some(password.to_string().into())
|
|
||||||
// }
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// Ok(Basic { user_id, password })
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[get("/login")]
|
|
||||||
async fn login(id: Identity) -> HttpResponse {
|
|
||||||
let maybe_identity = id.identity();
|
|
||||||
// id.remember("user1".to_owned());
|
|
||||||
let response = if let Some(identity) = maybe_identity {
|
|
||||||
HttpResponse::Ok()
|
|
||||||
.header("location", "/")
|
|
||||||
.content_type("text/plain")
|
|
||||||
.body(format!("Already logged in {}", identity))
|
|
||||||
} else {
|
|
||||||
id.remember("user1".to_owned());
|
|
||||||
HttpResponse::Found().header("location", "/").finish()
|
|
||||||
};
|
|
||||||
// HttpResponse::Found().header("location", "/").finish()
|
|
||||||
response
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/logout")]
|
|
||||||
async fn logout(id: Identity) -> HttpResponse {
|
|
||||||
let maybe_identity = id.identity();
|
|
||||||
// id.remember("user1".to_owned());
|
|
||||||
let response = if let Some(identity) = maybe_identity {
|
|
||||||
info!("Logging out {user}", user = identity);
|
|
||||||
id.forget();
|
|
||||||
HttpResponse::Found().header("location", "/").finish()
|
|
||||||
} else {
|
|
||||||
HttpResponse::Ok()
|
|
||||||
.header("location", "/")
|
|
||||||
.content_type("text/plain")
|
|
||||||
.body("Not logged in")
|
|
||||||
};
|
|
||||||
// id.forget();
|
|
||||||
// HttpResponse::Found().header("location", "/").finish()
|
|
||||||
response
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
async fn index2(id: Identity) -> String {
|
|
||||||
format!(
|
|
||||||
"Hello {}",
|
|
||||||
id.identity().unwrap_or_else(|| "Anonymous".to_owned())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_rt::main]
|
#[actix_rt::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
std::env::set_var("RUST_LOG", "debug");
|
std::env::set_var("RUST_LOG", "debug");
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
|
|
||||||
let user_service: Box<dyn UserService> = Box::new(UserServiceImpl::new());
|
let basic_auth_middleware = HttpAuthentication::basic(utils::auth::validator);
|
||||||
user_service.do_something();
|
|
||||||
|
|
||||||
fun1(user_service.as_ref());
|
|
||||||
|
|
||||||
let user_service_impl = UserServiceImpl::new();
|
|
||||||
fun2(user_service_impl);
|
|
||||||
|
|
||||||
let basic_auth_middleware = HttpAuthentication::basic(validator);
|
|
||||||
|
|
||||||
// fun1(Rc::clone(&user_service).as_ref());
|
|
||||||
// set up database connection pool
|
// set up database connection pool
|
||||||
let connspec = std::env::var("DATABASE_URL").expect("DATABASE_URL NOT FOUND");
|
let connspec = std::env::var("DATABASE_URL").expect("DATABASE_URL NOT FOUND");
|
||||||
let manager = ConnectionManager::<SqliteConnection>::new(connspec);
|
let manager = ConnectionManager::<SqliteConnection>::new(connspec);
|
||||||
@ -240,18 +104,18 @@ async fn main() -> std::io::Result<()> {
|
|||||||
CookieIdentityPolicy::new(&private_key)
|
CookieIdentityPolicy::new(&private_key)
|
||||||
.name("my-app-auth")
|
.name("my-app-auth")
|
||||||
.secure(false)
|
.secure(false)
|
||||||
.same_site(SameSite::Lax), // .same_site(),
|
.same_site(SameSite::Lax),
|
||||||
))
|
))
|
||||||
.wrap(middleware::Logger::default())
|
.wrap(middleware::Logger::default())
|
||||||
.service(web::scope("/chat").wrap(basic_auth_middleware.clone()))
|
.service(web::scope("/chat").wrap(basic_auth_middleware.clone()))
|
||||||
// .service(extract_my_obj)
|
// .service(extract_my_obj)
|
||||||
// .service(index)
|
// .service(index)
|
||||||
.service(get_user)
|
.service(routes::users::get_user)
|
||||||
.service(add_user)
|
.service(routes::users::add_user)
|
||||||
.service(get_all_users)
|
.service(routes::users::get_all_users)
|
||||||
.service(login)
|
.service(routes::auth::login)
|
||||||
.service(logout)
|
.service(routes::auth::logout)
|
||||||
.service(index2)
|
.service(routes::auth::index)
|
||||||
.service(fs::Files::new("/", "./static"))
|
.service(fs::Files::new("/", "./static"))
|
||||||
};
|
};
|
||||||
HttpServer::new(app).bind(addr)?.run().await
|
HttpServer::new(app).bind(addr)?.run().await
|
||||||
|
3
src/middlewares.rs
Normal file
3
src/middlewares.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod csrf;
|
||||||
|
|
||||||
|
pub use self::csrf::*;
|
276
src/middlewares/csrf.rs
Normal file
276
src/middlewares/csrf.rs
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
// //! A filter for cross-site request forgery (CSRF).
|
||||||
|
// //!
|
||||||
|
// //! This middleware is stateless and [based on request
|
||||||
|
// //! headers](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Verifying_Same_Origin_with_Standard_Headers).
|
||||||
|
// //!
|
||||||
|
// //! By default requests are allowed only if one of these is true:
|
||||||
|
// //!
|
||||||
|
// //! * The request method is safe (`GET`, `HEAD`, `OPTIONS`). It is the
|
||||||
|
// //! applications responsibility to ensure these methods cannot be used to
|
||||||
|
// //! execute unwanted actions. Note that upgrade requests for websockets are
|
||||||
|
// //! also considered safe.
|
||||||
|
// //! * The `Origin` header (added automatically by the browser) matches one
|
||||||
|
// //! of the allowed origins.
|
||||||
|
// //! * There is no `Origin` header but the `Referer` header matches one of
|
||||||
|
// //! the allowed origins.
|
||||||
|
// //!
|
||||||
|
// //! Use [`CsrfFilter::allow_xhr()`](struct.CsrfFilter.html#method.allow_xhr)
|
||||||
|
// //! if you want to allow requests with unprotected methods via
|
||||||
|
// //! [CORS](../cors/struct.Cors.html).
|
||||||
|
// //!
|
||||||
|
// //! # Example
|
||||||
|
// //!
|
||||||
|
// //! ```
|
||||||
|
// //! # extern crate actix_web;
|
||||||
|
// //! use actix_web::middleware::csrf;
|
||||||
|
// //! use actix_web::{http, App, HttpRequest, HttpResponse};
|
||||||
|
// //!
|
||||||
|
// //! fn handle_post(_: &HttpRequest) -> &'static str {
|
||||||
|
// //! "This action should only be triggered with requests from the same site"
|
||||||
|
// //! }
|
||||||
|
// //!
|
||||||
|
// //! fn main() {
|
||||||
|
// //! let app = App::new()
|
||||||
|
// //! .middleware(
|
||||||
|
// //! csrf::CsrfFilter::new().allowed_origin("https://www.example.com"),
|
||||||
|
// //! )
|
||||||
|
// //! .resource("/", |r| {
|
||||||
|
// //! r.method(http::Method::GET).f(|_| HttpResponse::Ok());
|
||||||
|
// //! r.method(http::Method::POST).f(handle_post);
|
||||||
|
// //! })
|
||||||
|
// //! .finish();
|
||||||
|
// //! }
|
||||||
|
// //! ```
|
||||||
|
// //!
|
||||||
|
// //! In this example the entire application is protected from CSRF.
|
||||||
|
|
||||||
|
// use std::borrow::Cow;
|
||||||
|
// use std::collections::HashSet;
|
||||||
|
|
||||||
|
// use bytes::Bytes;
|
||||||
|
// use error::{ResponseError, Result};
|
||||||
|
// use http::{header, HeaderMap, HttpTryFrom, Uri};
|
||||||
|
// use httprequest::HttpRequest;
|
||||||
|
// use httpresponse::HttpResponse;
|
||||||
|
// use middleware::{Middleware, Started};
|
||||||
|
// use server::Request;
|
||||||
|
|
||||||
|
// /// Potential cross-site request forgery detected.
|
||||||
|
// #[derive(Debug, Fail)]
|
||||||
|
// pub enum CsrfError {
|
||||||
|
// /// The HTTP request header `Origin` was required but not provided.
|
||||||
|
// #[fail(display = "Origin header required")]
|
||||||
|
// MissingOrigin,
|
||||||
|
// /// The HTTP request header `Origin` could not be parsed correctly.
|
||||||
|
// #[fail(display = "Could not parse Origin header")]
|
||||||
|
// BadOrigin,
|
||||||
|
// /// The cross-site request was denied.
|
||||||
|
// #[fail(display = "Cross-site request denied")]
|
||||||
|
// CsrDenied,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl ResponseError for CsrfError {
|
||||||
|
// fn error_response(&self) -> HttpResponse {
|
||||||
|
// HttpResponse::Forbidden().body(self.to_string())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn uri_origin(uri: &Uri) -> Option<String> {
|
||||||
|
// match (
|
||||||
|
// uri.scheme_part(),
|
||||||
|
// uri.host(),
|
||||||
|
// uri.port_part().map(|port| port.as_u16()),
|
||||||
|
// ) {
|
||||||
|
// (Some(scheme), Some(host), Some(port)) => Some(format!("{}://{}:{}", scheme, host, port)),
|
||||||
|
// (Some(scheme), Some(host), None) => Some(format!("{}://{}", scheme, host)),
|
||||||
|
// _ => None,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn origin(headers: &HeaderMap) -> Option<Result<Cow<str>, CsrfError>> {
|
||||||
|
// headers
|
||||||
|
// .get(header::ORIGIN)
|
||||||
|
// .map(|origin| {
|
||||||
|
// origin
|
||||||
|
// .to_str()
|
||||||
|
// .map_err(|_| CsrfError::BadOrigin)
|
||||||
|
// .map(|o| o.into())
|
||||||
|
// })
|
||||||
|
// .or_else(|| {
|
||||||
|
// headers.get(header::REFERER).map(|referer| {
|
||||||
|
// Uri::try_from(Bytes::from(referer.as_bytes()))
|
||||||
|
// .ok()
|
||||||
|
// .as_ref()
|
||||||
|
// .and_then(uri_origin)
|
||||||
|
// .ok_or(CsrfError::BadOrigin)
|
||||||
|
// .map(|o| o.into())
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// A middleware that filters cross-site requests.
|
||||||
|
// ///
|
||||||
|
// /// To construct a CSRF filter:
|
||||||
|
// ///
|
||||||
|
// /// 1. Call [`CsrfFilter::build`](struct.CsrfFilter.html#method.build) to
|
||||||
|
// /// start building.
|
||||||
|
// /// 2. [Add](struct.CsrfFilterBuilder.html#method.allowed_origin) allowed
|
||||||
|
// /// origins.
|
||||||
|
// /// 3. Call [finish](struct.CsrfFilterBuilder.html#method.finish) to retrieve
|
||||||
|
// /// the constructed filter.
|
||||||
|
// ///
|
||||||
|
// /// # Example
|
||||||
|
// ///
|
||||||
|
// /// ```
|
||||||
|
// /// use actix_web::middleware::csrf;
|
||||||
|
// /// use actix_web::App;
|
||||||
|
// ///
|
||||||
|
// /// # fn main() {
|
||||||
|
// /// let app = App::new()
|
||||||
|
// /// .middleware(csrf::CsrfFilter::new().allowed_origin("https://www.example.com"));
|
||||||
|
// /// # }
|
||||||
|
// /// ```
|
||||||
|
// #[derive(Default)]
|
||||||
|
// pub struct CsrfFilter {
|
||||||
|
// origins: HashSet<String>,
|
||||||
|
// allow_xhr: bool,
|
||||||
|
// allow_missing_origin: bool,
|
||||||
|
// allow_upgrade: bool,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl CsrfFilter {
|
||||||
|
// /// Start building a `CsrfFilter`.
|
||||||
|
// pub fn new() -> CsrfFilter {
|
||||||
|
// CsrfFilter {
|
||||||
|
// origins: HashSet::new(),
|
||||||
|
// allow_xhr: false,
|
||||||
|
// allow_missing_origin: false,
|
||||||
|
// allow_upgrade: false,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Add an origin that is allowed to make requests. Will be verified
|
||||||
|
// /// against the `Origin` request header.
|
||||||
|
// pub fn allowed_origin<T: Into<String>>(mut self, origin: T) -> CsrfFilter {
|
||||||
|
// self.origins.insert(origin.into());
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Allow all requests with an `X-Requested-With` header.
|
||||||
|
// ///
|
||||||
|
// /// A cross-site attacker should not be able to send requests with custom
|
||||||
|
// /// headers unless a CORS policy whitelists them. Therefore it should be
|
||||||
|
// /// safe to allow requests with an `X-Requested-With` header (added
|
||||||
|
// /// automatically by many JavaScript libraries).
|
||||||
|
// ///
|
||||||
|
// /// This is disabled by default, because in Safari it is possible to
|
||||||
|
// /// circumvent this using redirects and Flash.
|
||||||
|
// ///
|
||||||
|
// /// Use this method to enable more lax filtering.
|
||||||
|
// pub fn allow_xhr(mut self) -> CsrfFilter {
|
||||||
|
// self.allow_xhr = true;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Allow requests if the expected `Origin` header is missing (and
|
||||||
|
// /// there is no `Referer` to fall back on).
|
||||||
|
// ///
|
||||||
|
// /// The filter is conservative by default, but it should be safe to allow
|
||||||
|
// /// missing `Origin` headers because a cross-site attacker cannot prevent
|
||||||
|
// /// the browser from sending `Origin` on unprotected requests.
|
||||||
|
// pub fn allow_missing_origin(mut self) -> CsrfFilter {
|
||||||
|
// self.allow_missing_origin = true;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Allow cross-site upgrade requests (for example to open a WebSocket).
|
||||||
|
// pub fn allow_upgrade(mut self) -> CsrfFilter {
|
||||||
|
// self.allow_upgrade = true;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn validate(&self, req: &Request) -> Result<(), CsrfError> {
|
||||||
|
// let is_upgrade = req.headers().contains_key(header::UPGRADE);
|
||||||
|
// let is_safe = req.method().is_safe() && (self.allow_upgrade || !is_upgrade);
|
||||||
|
|
||||||
|
// if is_safe || (self.allow_xhr && req.headers().contains_key("x-requested-with")) {
|
||||||
|
// Ok(())
|
||||||
|
// } else if let Some(header) = origin(req.headers()) {
|
||||||
|
// match header {
|
||||||
|
// Ok(ref origin) if self.origins.contains(origin.as_ref()) => Ok(()),
|
||||||
|
// Ok(_) => Err(CsrfError::CsrDenied),
|
||||||
|
// Err(err) => Err(err),
|
||||||
|
// }
|
||||||
|
// } else if self.allow_missing_origin {
|
||||||
|
// Ok(())
|
||||||
|
// } else {
|
||||||
|
// Err(CsrfError::MissingOrigin)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<S> Middleware<S> for CsrfFilter {
|
||||||
|
// fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
|
||||||
|
// self.validate(req)?;
|
||||||
|
// Ok(Started::Done)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[cfg(test)]
|
||||||
|
// mod tests {
|
||||||
|
// use super::*;
|
||||||
|
// use http::Method;
|
||||||
|
// use test::TestRequest;
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_safe() {
|
||||||
|
// let csrf = CsrfFilter::new().allowed_origin("https://www.example.com");
|
||||||
|
|
||||||
|
// let req = TestRequest::with_header("Origin", "https://www.w3.org")
|
||||||
|
// .method(Method::HEAD)
|
||||||
|
// .finish();
|
||||||
|
|
||||||
|
// assert!(csrf.start(&req).is_ok());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_csrf() {
|
||||||
|
// let csrf = CsrfFilter::new().allowed_origin("https://www.example.com");
|
||||||
|
|
||||||
|
// let req = TestRequest::with_header("Origin", "https://www.w3.org")
|
||||||
|
// .method(Method::POST)
|
||||||
|
// .finish();
|
||||||
|
|
||||||
|
// assert!(csrf.start(&req).is_err());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_referer() {
|
||||||
|
// let csrf = CsrfFilter::new().allowed_origin("https://www.example.com");
|
||||||
|
|
||||||
|
// let req =
|
||||||
|
// TestRequest::with_header("Referer", "https://www.example.com/some/path?query=param")
|
||||||
|
// .method(Method::POST)
|
||||||
|
// .finish();
|
||||||
|
|
||||||
|
// assert!(csrf.start(&req).is_ok());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_upgrade() {
|
||||||
|
// let strict_csrf = CsrfFilter::new().allowed_origin("https://www.example.com");
|
||||||
|
|
||||||
|
// let lax_csrf = CsrfFilter::new()
|
||||||
|
// .allowed_origin("https://www.example.com")
|
||||||
|
// .allow_upgrade();
|
||||||
|
|
||||||
|
// let req = TestRequest::with_header("Origin", "https://cswsh.com")
|
||||||
|
// .header("Connection", "Upgrade")
|
||||||
|
// .header("Upgrade", "websocket")
|
||||||
|
// .method(Method::GET)
|
||||||
|
// .finish();
|
||||||
|
|
||||||
|
// assert!(strict_csrf.start(&req).is_err());
|
||||||
|
// assert!(lax_csrf.start(&req).is_ok());
|
||||||
|
// }
|
||||||
|
// }
|
@ -1,24 +1,4 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
pub mod users;
|
||||||
|
pub use self::users::*;
|
||||||
use crate::schema::users;
|
pub mod errors;
|
||||||
use yarte::Template;
|
pub use self::errors::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Queryable, Identifiable, Deserialize)]
|
|
||||||
pub struct User {
|
|
||||||
pub id: i32,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Insertable, Deserialize)]
|
|
||||||
#[table_name = "users"]
|
|
||||||
pub struct NewUser {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Template)]
|
|
||||||
#[template(path = "hello.hbs")]
|
|
||||||
pub struct CardTemplate<'a> {
|
|
||||||
pub title: &'a str,
|
|
||||||
pub body: String,
|
|
||||||
pub num: u32,
|
|
||||||
}
|
|
||||||
|
13
src/models/errors.rs
Normal file
13
src/models/errors.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct JsonErrorModel {
|
||||||
|
status_code: i16,
|
||||||
|
pub line: String,
|
||||||
|
pub reason: String,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct ErrorModel {
|
||||||
|
pub status_code: i16,
|
||||||
|
pub reason: String,
|
||||||
|
}
|
0
src/models/roles.rs
Normal file
0
src/models/roles.rs
Normal file
38
src/models/users.rs
Normal file
38
src/models/users.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::schema::users;
|
||||||
|
use crate::utils::regexs;
|
||||||
|
use chrono;
|
||||||
|
use validator::Validate;
|
||||||
|
use validator_derive::*;
|
||||||
|
use yarte::Template;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Queryable, Identifiable, Deserialize, PartialEq)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub password: String,
|
||||||
|
pub created_at: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Insertable, Deserialize, Validate)]
|
||||||
|
#[table_name = "users"]
|
||||||
|
pub struct NewUser {
|
||||||
|
#[validate(regex = "regexs::USERNAME_REG", length(min = 4, max = 10))]
|
||||||
|
pub name: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Queryable)]
|
||||||
|
pub struct UserDTO {
|
||||||
|
pub name: String,
|
||||||
|
pub registration_date: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "hello.hbs")]
|
||||||
|
pub struct CardTemplate<'a> {
|
||||||
|
pub title: &'a str,
|
||||||
|
pub body: String,
|
||||||
|
pub num: u32,
|
||||||
|
}
|
@ -1,2 +1,4 @@
|
|||||||
|
pub mod auth;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
pub use self::auth::*;
|
||||||
pub use self::users::*;
|
pub use self::users::*;
|
||||||
|
45
src/routes/auth.rs
Normal file
45
src/routes/auth.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use actix_web_httpauth::extractors::basic::BasicAuth;
|
||||||
|
|
||||||
|
use actix_identity::Identity;
|
||||||
|
use actix_web::{get, post, Error, HttpResponse};
|
||||||
|
|
||||||
|
#[get("/login")]
|
||||||
|
pub async fn login(id: Identity, credentials: BasicAuth) -> Result<HttpResponse, Error> {
|
||||||
|
let maybe_identity = id.identity();
|
||||||
|
let response = if let Some(identity) = maybe_identity {
|
||||||
|
HttpResponse::Found()
|
||||||
|
.header("location", "/")
|
||||||
|
.content_type("text/plain")
|
||||||
|
.json(format!("Already logged in as {}", identity))
|
||||||
|
} else {
|
||||||
|
id.remember(credentials.user_id().to_string());
|
||||||
|
HttpResponse::Found().header("location", "/").finish()
|
||||||
|
};
|
||||||
|
println!("{}", credentials.user_id());
|
||||||
|
println!("{:?}", credentials.password());
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/logout")]
|
||||||
|
pub async fn logout(id: Identity, _credentials: BasicAuth) -> Result<HttpResponse, Error> {
|
||||||
|
let maybe_identity = id.identity();
|
||||||
|
let response = if let Some(identity) = maybe_identity {
|
||||||
|
info!("Logging out {user}", user = identity);
|
||||||
|
id.forget();
|
||||||
|
HttpResponse::Found().header("location", "/").finish()
|
||||||
|
} else {
|
||||||
|
HttpResponse::Found()
|
||||||
|
.header("location", "/")
|
||||||
|
.content_type("text/plain")
|
||||||
|
.json("Not logged in")
|
||||||
|
};
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
pub async fn index(id: Identity) -> String {
|
||||||
|
format!(
|
||||||
|
"Hello {}",
|
||||||
|
id.identity().unwrap_or_else(|| "Anonymous".to_owned())
|
||||||
|
)
|
||||||
|
}
|
@ -1,76 +1,82 @@
|
|||||||
use actix_web::{get, post, web, Error, HttpResponse};
|
use actix_web::{get, post, web, HttpResponse};
|
||||||
|
|
||||||
use crate::actions;
|
use crate::actions;
|
||||||
use crate::models;
|
use crate::models;
|
||||||
use crate::types::DbPool;
|
use crate::types::DbPool;
|
||||||
|
use actix_web::error::ResponseError;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Finds user by UID.
|
/// Finds user by UID.
|
||||||
#[get("/api/authzd/users/get/{user_id}")]
|
#[get("/api/authzd/users/get/{user_id}")]
|
||||||
pub async fn get_user(
|
pub async fn get_user(
|
||||||
pool: web::Data<DbPool>,
|
pool: web::Data<DbPool>,
|
||||||
user_uid: web::Path<i32>,
|
user_uid: web::Path<i32>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, impl ResponseError> {
|
||||||
let user_uid = user_uid.into_inner();
|
let user_uid = user_uid.into_inner();
|
||||||
// use web::block to offload blocking Diesel code without blocking server thread
|
// use web::block to offload blocking Diesel code without blocking server thread
|
||||||
let maybe_user = web::block(move || {
|
let res = web::block(move || {
|
||||||
let conn = pool.get().map_err(|e| e.to_string())?;
|
let conn = pool.get()?;
|
||||||
actions::find_user_by_uid(user_uid.into(), &conn).map_err(|e| e.to_string())
|
actions::find_user_by_uid(user_uid, &conn)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.and_then(|maybe_user| {
|
||||||
error!("{}", e);
|
|
||||||
HttpResponse::InternalServerError().finish()
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if let Some(user) = maybe_user {
|
if let Some(user) = maybe_user {
|
||||||
Ok(HttpResponse::Ok().json(user))
|
Ok(HttpResponse::Ok().json(user))
|
||||||
} else {
|
} else {
|
||||||
let res = HttpResponse::NotFound().body(format!("No user found with uid: {}", user_uid));
|
let res =
|
||||||
|
HttpResponse::NotFound().body(format!("No user found with uid: {}", user_uid));
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/api/authzd/users/get")]
|
#[get("/api/authzd/users/get")]
|
||||||
pub async fn get_all_users(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
|
pub async fn get_all_users(pool: web::Data<DbPool>) -> Result<HttpResponse, impl ResponseError> {
|
||||||
// use web::block to offload blocking Diesel code without blocking server thread
|
// use web::block to offload blocking Diesel code without blocking server thread
|
||||||
let maybe_users = web::block(move || {
|
let res = web::block(move || {
|
||||||
let conn = pool.get().map_err(|e| e.to_string())?;
|
let conn = pool.get()?;
|
||||||
actions::get_all(&conn).map_err(|e| e.to_string())
|
actions::get_all(&conn)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.and_then(|maybe_users| {
|
||||||
eprintln!("{}", e);
|
debug!("{:?}", maybe_users);
|
||||||
HttpResponse::InternalServerError().finish()
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if let Some(users) = maybe_users {
|
if let Some(users) = maybe_users {
|
||||||
Ok(HttpResponse::Ok().json(users))
|
if users.is_empty() {
|
||||||
|
let res = HttpResponse::Ok().json(models::ErrorModel {
|
||||||
|
status_code: 200,
|
||||||
|
reason: "No users available".to_string(),
|
||||||
|
});
|
||||||
|
Ok(res)
|
||||||
} else {
|
} else {
|
||||||
let res = HttpResponse::NotFound().body(format!("No users available"));
|
Ok(HttpResponse::Ok().json(users))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let res = HttpResponse::Ok().json(models::ErrorModel {
|
||||||
|
status_code: 200,
|
||||||
|
reason: "No users available".to_string(),
|
||||||
|
});
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
// Ok(HttpResponse::Ok().json(users))
|
});
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts new user with name defined in form.
|
/// Inserts new user with name defined in form.
|
||||||
#[post("/api/authzd/users/post")]
|
#[post("/do_registration")]
|
||||||
pub async fn add_user(
|
pub async fn add_user(
|
||||||
pool: web::Data<DbPool>,
|
pool: web::Data<DbPool>,
|
||||||
form: web::Json<models::NewUser>,
|
form: web::Json<models::NewUser>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, impl ResponseError> {
|
||||||
// use web::block to offload blocking Diesel code without blocking server thread
|
// use web::block to offload blocking Diesel code without blocking server thread
|
||||||
let user = web::block(move || {
|
let user = web::block(move || {
|
||||||
let conn = pool.get().map_err(|e| e.to_string())?;
|
let conn = pool.get()?;
|
||||||
actions::insert_new_user(&form, &conn).map_err(|e| e.to_string())
|
actions::insert_new_user(Rc::new(form.0), &conn)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map(|user| {
|
.and_then(|user| {
|
||||||
debug!("{:?}", user);
|
debug!("{:?}", user);
|
||||||
Ok(HttpResponse::Ok().json(user))
|
Ok(HttpResponse::Created().json(user))
|
||||||
})
|
});
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("{}", e);
|
|
||||||
HttpResponse::InternalServerError().finish()
|
|
||||||
})?;
|
|
||||||
user
|
user
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,7 @@ table! {
|
|||||||
users (id) {
|
users (id) {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
name -> Text,
|
name -> Text,
|
||||||
|
password -> Text,
|
||||||
|
created_at -> Timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
src/utils.rs
Normal file
4
src/utils.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod auth;
|
||||||
|
pub mod regexs;
|
||||||
|
pub use self::auth::*;
|
||||||
|
pub use self::regexs::*;
|
14
src/utils/auth.rs
Normal file
14
src/utils/auth.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use actix_web_httpauth::extractors::basic::BasicAuth;
|
||||||
|
|
||||||
|
// use actix_identity::Identity;
|
||||||
|
use actix_web::{dev::ServiceRequest, Error};
|
||||||
|
|
||||||
|
pub async fn validator(
|
||||||
|
req: ServiceRequest,
|
||||||
|
credentials: BasicAuth,
|
||||||
|
) -> Result<ServiceRequest, Error> {
|
||||||
|
println!("{}", credentials.user_id());
|
||||||
|
println!("{:?}", credentials.password());
|
||||||
|
// verify credentials from db
|
||||||
|
Ok(req)
|
||||||
|
}
|
5
src/utils/regexs.rs
Normal file
5
src/utils/regexs.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref USERNAME_REG: Regex = Regex::new(r"^([a-z\d]+-)*[a-z\d]+$").unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user