/target
.env
.idea
+env_setup.sh
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "ascii_utils"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "atty"
version = "0.2.13"
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "base64"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "base64"
version = "0.10.1"
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "bufstream"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "byteorder"
version = "1.3.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "core-foundation"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "crc32fast"
version = "1.2.0"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "email"
+version = "0.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "encoding"
version = "0.2.33"
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "fast_chemail"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "flate2"
version = "1.0.9"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonwebtoken 6.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lettre_email 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
"strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "lettre"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lettre_email"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "email 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "libc"
version = "0.2.60"
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "native-tls"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.52 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "net2"
version = "0.2.33"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "openssl"
+version = "0.10.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.52 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "owning_ref"
version = "0.4.0"
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "pkg-config"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "ppv-lite86"
version = "0.2.5"
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rand"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rand"
version = "0.6.5"
"ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "remove_dir_all"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "resolv-conf"
version = "0.6.2"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "schannel"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "scopeguard"
version = "0.3.3"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "security-framework"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "semver"
version = "0.9.0"
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "tempfile"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "termcolor"
version = "1.0.5"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "uuid"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "v_escape"
version = "0.7.2"
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum aho-corasick 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b7aa1ccb7d7ea3f437cf025a2ab1c47cc6c1bc9fc84918ff449def12f5e282"
"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
+"checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
"checksum awc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4c4763e6aa29a801d761dc3464f081d439ea5249ba90c3c3bdfc8dd3f739d233"
"checksum backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)" = "88fb679bc9af8fa639198790a77f52d345fe13656c08b43afa9424c206b731c6"
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
+"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
"checksum bcrypt 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4fd6a91ff640809cfab4ea74312a892238a7bbae53adbf717b71122deb0c85"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
"checksum brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd"
"checksum brotli2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e"
+"checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127"
+"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
+"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
"checksum dotenv 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4424bad868b0ffe6ae351ee463526ba625bbca817978293bbe6bb7dc1804a175"
"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
+"checksum email 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "91549a51bb0241165f13d57fc4c72cef063b4088fb078b019ecbf464a45f22e4"
"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
"checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
"checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
+"checksum fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4"
"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
+"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
+"checksum lettre 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66afaa5dfadbb81d4e00fd1d1ab057c7cd4c799c5a44e0009386d553587e728"
+"checksum lettre_email 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bbb68ca999042d965476e47bbdbacd52db0927348b6f8062c44dd04a3b1fd43b"
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
+"checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449"
+"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
+"checksum openssl-sys 0.9.52 (registry+https://github.com/rust-lang/crates.io-index)" = "c977d08e1312e2f7e4b86f9ebaa0ed3b19d1daff75fae88bbb88108afbd801fc"
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
+"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum pq-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
+"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b23da8dfd98a84bd7e08700190a5d9f7d2d38abd4369dd1dae651bc40bfd2cc"
"checksum regex-syntax 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5485bf1523a9ed51c4964273f22f63f24e31632adb5dad134f488f86a3875c"
+"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb"
"checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
+"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
+"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
+"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.97 (registry+https://github.com/rust-lang/crates.io-index)" = "d46b3dfedb19360a74316866cef04687cd4d6a70df8e6a506c63512790769b72"
"checksum syn 0.15.40 (registry+https://github.com/rust-lang/crates.io-index)" = "bc945221ccf4a7e8c31222b9d1fc77aefdd6638eb901a6ce457a3dc29d4c31e8"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
+"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
+"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
"checksum v_escape 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8865501b78eef9193c1b45486acf18ba889e5662eba98854d6fc59d8ecf3542d"
"checksum v_escape_derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "306896ff4b75998501263a1dc000456de442e21d68fe8c8bdf75c66a33a58e23"
"checksum v_htmlescape 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbbe0fa88dd36f9c8cf61a218d4b953ba669de4d0785832f33cc72bd081e1be"
jsonwebtoken = "6.0.1"
regex = "1.1.9"
lazy_static = "1.3.0"
-
--- /dev/null
+drop table password_reset_request;
--- /dev/null
+create table password_reset_request (
+ id serial primary key,
+ user_id int references user_ on update cascade on delete cascade not null,
+ token_encrypted text not null,
+ published timestamp not null default now()
+);
use crate::db::user_mention::*;
use crate::db::user_mention_view::*;
use crate::db::user_view::*;
+use crate::db::password_reset_request::*;
use crate::db::*;
use crate::{extract_usernames, has_slurs, naive_from_unix, naive_now, remove_slurs, Settings};
use failure::Error;
TransferCommunity,
TransferSite,
DeleteAccount,
+ PasswordReset,
+ PasswordChange,
}
#[derive(Fail, Debug)]
use super::*;
use bcrypt::verify;
use std::str::FromStr;
+use crate::{generate_random_string,send_email};
#[derive(Serialize, Deserialize, Debug)]
pub struct Login {
auth: String,
}
+
+#[derive(Serialize, Deserialize)]
+pub struct PasswordReset {
+ email: String,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct PasswordResetResponse {
+ op: String,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct PasswordChange {
+ token: String,
+ password: String,
+ password_verify: String,
+}
+
impl Perform<LoginResponse> for Oper<Login> {
fn perform(&self) -> Result<LoginResponse, Error> {
let data: &Login = &self.data;
})
}
}
+
+impl Perform<PasswordResetResponse> for Oper<PasswordReset> {
+ fn perform(&self) -> Result<PasswordResetResponse, Error> {
+ let data: &PasswordReset = &self.data;
+ let conn = establish_connection();
+
+ // Fetch that email
+ let user: User_ = match User_::find_by_email(&conn, &data.email) {
+ Ok(user) => user,
+ Err(_e) => {
+ return Err(APIError::err(
+ &self.op,
+ "couldnt_find_that_username_or_email",
+ ))?
+ }
+ };
+
+ // Generate a random token
+ let token = generate_random_string();
+
+ // Insert the row
+ PasswordResetRequest::create_token(&conn, user.id, &token)?;
+
+ // Email the pure token to the user.
+ // TODO no i18n support here.
+ let user_email = &user.email.expect("email");
+ let subject = &format!("Password reset for {}", user.name);
+ let hostname = Settings::get().hostname;
+ let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/{}>Click here to reset your password</a>", user.name, hostname, &token);
+ match send_email(subject, user_email, &user.name, html) {
+ Ok(_o) => _o,
+ Err(_e) => {
+ return Err(APIError::err(
+ &self.op,
+ &_e.to_string(),
+ ))?
+ }
+ };
+
+ Ok(PasswordResetResponse {
+ op: self.op.to_string(),
+ })
+ }
+}
+
+impl Perform<LoginResponse> for Oper<PasswordChange> {
+ fn perform(&self) -> Result<LoginResponse, Error> {
+ let data: &PasswordChange = &self.data;
+ let conn = establish_connection();
+
+ // Fetch the user_id from the token
+ let user_id = PasswordResetRequest::read_from_token(&conn, &data.token)?.user_id;
+
+ // Make sure passwords match
+ if &data.password != &data.password_verify {
+ return Err(APIError::err(&self.op, "passwords_dont_match"))?;
+ }
+
+ // Fetch the user
+ let read_user = User_::read(&conn, user_id)?;
+
+ // Update the user with the new password
+ let user_form = UserForm {
+ name: read_user.name,
+ fedi_name: read_user.fedi_name,
+ email: read_user.email,
+ password_encrypted: data.password.to_owned(),
+ preferred_username: read_user.preferred_username,
+ updated: Some(naive_now()),
+ admin: read_user.admin,
+ banned: read_user.banned,
+ show_nsfw: read_user.show_nsfw,
+ theme: read_user.theme,
+ default_sort_type: read_user.default_sort_type,
+ default_listing_type: read_user.default_listing_type,
+ };
+
+ let updated_user = match User_::update_password(&conn, user_id, &user_form) {
+ Ok(user) => user,
+ Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user"))?,
+ };
+
+ // Return the jwt
+ Ok(LoginResponse {
+ op: self.op.to_string(),
+ jwt: updated_user.jwt(),
+ })
+ }
+}
pub mod user_mention;
pub mod user_mention_view;
pub mod user_view;
+pub mod password_reset_request;
pub trait Crud<T> {
fn create(conn: &PgConnection, form: &T) -> Result<Self, Error>
--- /dev/null
+use super::*;
+use crate::schema::password_reset_request;
+use crate::schema::password_reset_request::dsl::*;
+
+use bcrypt::{hash, DEFAULT_COST};
+
+#[derive(Queryable, Identifiable, PartialEq, Debug)]
+#[table_name = "password_reset_request"]
+pub struct PasswordResetRequest {
+ pub id: i32,
+ pub user_id: i32,
+ pub token_encrypted: String,
+ pub published: chrono::NaiveDateTime,
+}
+
+#[derive(Insertable, AsChangeset, Clone)]
+#[table_name = "password_reset_request"]
+pub struct PasswordResetRequestForm {
+ pub user_id: i32,
+ pub token_encrypted: String,
+}
+
+impl Crud<PasswordResetRequestForm> for PasswordResetRequest {
+ fn read(conn: &PgConnection, password_reset_request_id: i32) -> Result<Self, Error> {
+ use crate::schema::password_reset_request::dsl::*;
+ password_reset_request.find(password_reset_request_id).first::<Self>(conn)
+ }
+ fn delete(conn: &PgConnection, password_reset_request_id: i32) -> Result<usize, Error> {
+ diesel::delete(password_reset_request.find(password_reset_request_id)).execute(conn)
+ }
+ fn create(conn: &PgConnection, form: &PasswordResetRequestForm) -> Result<Self, Error> {
+ insert_into(password_reset_request).values(form).get_result::<Self>(conn)
+ }
+ fn update(conn: &PgConnection, password_reset_request_id: i32, form: &PasswordResetRequestForm) -> Result<Self, Error> {
+ diesel::update(password_reset_request.find(password_reset_request_id))
+ .set(form)
+ .get_result::<Self>(conn)
+ }
+}
+
+impl PasswordResetRequest {
+ pub fn create_token(conn: &PgConnection, from_user_id: i32, token: &str) -> Result<Self, Error> {
+ let token_hash =
+ hash(token, DEFAULT_COST).expect("Couldn't hash token");
+
+ let form = PasswordResetRequestForm {
+ user_id: from_user_id,
+ token_encrypted: token_hash,
+ };
+
+ Self::create(&conn, &form)
+ }
+ pub fn read_from_token(conn: &PgConnection, token: &str) -> Result<Self, Error> {
+ let token_hash =
+ hash(token, DEFAULT_COST).expect("Couldn't hash token");
+
+ password_reset_request.filter(token_encrypted.eq(token_hash)).first::<Self>(conn)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use super::super::user::*;
+
+ #[test]
+ fn test_crud() {
+ let conn = establish_connection();
+
+ let new_user = UserForm {
+ name: "thommy prw".into(),
+ fedi_name: "rrf".into(),
+ preferred_username: None,
+ password_encrypted: "nope".into(),
+ email: None,
+ admin: false,
+ banned: false,
+ updated: None,
+ show_nsfw: false,
+ theme: "darkly".into(),
+ default_sort_type: SortType::Hot as i16,
+ default_listing_type: ListingType::Subscribed as i16,
+ };
+
+ let inserted_user = User_::create(&conn, &new_user).unwrap();
+
+ let new_password_reset_request = PasswordResetRequestForm {
+ user_id: inserted_user.id,
+ token_encrypted: "no".into(),
+ };
+
+ let inserted_password_reset_request = PasswordResetRequest::create(&conn, &new_password_reset_request).unwrap();
+
+ let expected_password_reset_request = PasswordResetRequest {
+ id: inserted_password_reset_request.id,
+ user_id: inserted_user.id,
+ token_encrypted: "no".into(),
+ published: inserted_password_reset_request.published,
+ };
+
+ let read_password_reset_request = PasswordResetRequest::read(&conn, inserted_password_reset_request.id).unwrap();
+ let num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
+
+ assert_eq!(expected_password_reset_request, read_password_reset_request);
+ assert_eq!(expected_password_reset_request, inserted_password_reset_request);
+ assert_eq!(1, num_deleted);
+ }
+}
+++ /dev/null
-table! {
- category (id) {
- id -> Int4,
- name -> Varchar,
- }
-}
-
-table! {
- comment (id) {
- id -> Int4,
- creator_id -> Int4,
- post_id -> Int4,
- parent_id -> Nullable<Int4>,
- content -> Text,
- removed -> Bool,
- read -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- deleted -> Bool,
- }
-}
-
-table! {
- comment_like (id) {
- id -> Int4,
- user_id -> Int4,
- comment_id -> Int4,
- post_id -> Int4,
- score -> Int2,
- published -> Timestamp,
- }
-}
-
-table! {
- comment_saved (id) {
- id -> Int4,
- comment_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- community (id) {
- id -> Int4,
- name -> Varchar,
- title -> Varchar,
- description -> Nullable<Text>,
- category_id -> Int4,
- creator_id -> Int4,
- removed -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- deleted -> Bool,
- nsfw -> Bool,
- }
-}
-
-table! {
- community_follower (id) {
- id -> Int4,
- community_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- community_moderator (id) {
- id -> Int4,
- community_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- community_user_ban (id) {
- id -> Int4,
- community_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- mod_add (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_add_community (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- community_id -> Int4,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_ban (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- reason -> Nullable<Text>,
- banned -> Nullable<Bool>,
- expires -> Nullable<Timestamp>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_ban_from_community (id) {
- id -> Int4,
- mod_user_id -> Int4,
- other_user_id -> Int4,
- community_id -> Int4,
- reason -> Nullable<Text>,
- banned -> Nullable<Bool>,
- expires -> Nullable<Timestamp>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_lock_post (id) {
- id -> Int4,
- mod_user_id -> Int4,
- post_id -> Int4,
- locked -> Nullable<Bool>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_remove_comment (id) {
- id -> Int4,
- mod_user_id -> Int4,
- comment_id -> Int4,
- reason -> Nullable<Text>,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_remove_community (id) {
- id -> Int4,
- mod_user_id -> Int4,
- community_id -> Int4,
- reason -> Nullable<Text>,
- removed -> Nullable<Bool>,
- expires -> Nullable<Timestamp>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_remove_post (id) {
- id -> Int4,
- mod_user_id -> Int4,
- post_id -> Int4,
- reason -> Nullable<Text>,
- removed -> Nullable<Bool>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- mod_sticky_post (id) {
- id -> Int4,
- mod_user_id -> Int4,
- post_id -> Int4,
- stickied -> Nullable<Bool>,
- when_ -> Timestamp,
- }
-}
-
-table! {
- post (id) {
- id -> Int4,
- name -> Varchar,
- url -> Nullable<Text>,
- body -> Nullable<Text>,
- creator_id -> Int4,
- community_id -> Int4,
- removed -> Bool,
- locked -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- deleted -> Bool,
- nsfw -> Bool,
- stickied -> Bool,
- }
-}
-
-table! {
- post_like (id) {
- id -> Int4,
- post_id -> Int4,
- user_id -> Int4,
- score -> Int2,
- published -> Timestamp,
- }
-}
-
-table! {
- post_read (id) {
- id -> Int4,
- post_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- post_saved (id) {
- id -> Int4,
- post_id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- site (id) {
- id -> Int4,
- name -> Varchar,
- description -> Nullable<Text>,
- creator_id -> Int4,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- }
-}
-
-table! {
- user_ (id) {
- id -> Int4,
- name -> Varchar,
- fedi_name -> Varchar,
- preferred_username -> Nullable<Varchar>,
- password_encrypted -> Text,
- email -> Nullable<Text>,
- icon -> Nullable<Bytea>,
- admin -> Bool,
- banned -> Bool,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- show_nsfw -> Bool,
- theme -> Varchar,
- }
-}
-
-table! {
- user_ban (id) {
- id -> Int4,
- user_id -> Int4,
- published -> Timestamp,
- }
-}
-
-table! {
- user_mention (id) {
- id -> Int4,
- recipient_id -> Int4,
- comment_id -> Int4,
- read -> Bool,
- published -> Timestamp,
- }
-}
-
-joinable!(comment -> post (post_id));
-joinable!(comment -> user_ (creator_id));
-joinable!(comment_like -> comment (comment_id));
-joinable!(comment_like -> post (post_id));
-joinable!(comment_like -> user_ (user_id));
-joinable!(comment_saved -> comment (comment_id));
-joinable!(comment_saved -> user_ (user_id));
-joinable!(community -> category (category_id));
-joinable!(community -> user_ (creator_id));
-joinable!(community_follower -> community (community_id));
-joinable!(community_follower -> user_ (user_id));
-joinable!(community_moderator -> community (community_id));
-joinable!(community_moderator -> user_ (user_id));
-joinable!(community_user_ban -> community (community_id));
-joinable!(community_user_ban -> user_ (user_id));
-joinable!(mod_add_community -> community (community_id));
-joinable!(mod_ban_from_community -> community (community_id));
-joinable!(mod_lock_post -> post (post_id));
-joinable!(mod_lock_post -> user_ (mod_user_id));
-joinable!(mod_remove_comment -> comment (comment_id));
-joinable!(mod_remove_comment -> user_ (mod_user_id));
-joinable!(mod_remove_community -> community (community_id));
-joinable!(mod_remove_community -> user_ (mod_user_id));
-joinable!(mod_remove_post -> post (post_id));
-joinable!(mod_remove_post -> user_ (mod_user_id));
-joinable!(mod_sticky_post -> post (post_id));
-joinable!(mod_sticky_post -> user_ (mod_user_id));
-joinable!(post -> community (community_id));
-joinable!(post -> user_ (creator_id));
-joinable!(post_like -> post (post_id));
-joinable!(post_like -> user_ (user_id));
-joinable!(post_read -> post (post_id));
-joinable!(post_read -> user_ (user_id));
-joinable!(post_saved -> post (post_id));
-joinable!(post_saved -> user_ (user_id));
-joinable!(site -> user_ (creator_id));
-joinable!(user_ban -> user_ (user_id));
-joinable!(user_mention -> comment (comment_id));
-joinable!(user_mention -> user_ (recipient_id));
-
-allow_tables_to_appear_in_same_query!(
- category,
- comment,
- comment_like,
- comment_saved,
- community,
- community_follower,
- community_moderator,
- community_user_ban,
- mod_add,
- mod_add_community,
- mod_ban,
- mod_ban_from_community,
- mod_lock_post,
- mod_remove_comment,
- mod_remove_community,
- mod_remove_post,
- mod_sticky_post,
- post,
- post_like,
- post_read,
- post_saved,
- site,
- user_,
- user_ban,
- user_mention,
-);
impl Crud<UserForm> for User_ {
fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
- use crate::schema::user_::dsl::*;
user_.find(user_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> {
Self::create(&conn, &edited_user)
}
+
+ pub fn update_password(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> {
+ let mut edited_user = form.clone();
+ let password_hash =
+ hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
+ edited_user.password_encrypted = password_hash;
+
+ Self::update(&conn, user_id, &edited_user)
+ }
+
pub fn read_from_name(conn: &PgConnection, from_user_name: String) -> Result<Self, Error> {
user_.filter(name.eq(from_user_name)).first::<Self>(conn)
}
.first::<User_>(conn)
}
}
+
+ pub fn find_by_email(
+ conn: &PgConnection,
+ from_email: &str,
+ ) -> Result<Self, Error> {
+ user_
+ .filter(email.eq(from_email))
+ .first::<User_>(conn)
+ }
+
pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> {
let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims;
#[cfg(test)]
mod tests {
use super::*;
+ use super::User_;
+
#[test]
fn test_crud() {
let conn = establish_connection();
pub extern crate serde;
pub extern crate serde_json;
pub extern crate strum;
+pub extern crate lettre;
+pub extern crate lettre_email;
pub mod api;
pub mod apub;
use dotenv::dotenv;
use regex::Regex;
use std::env;
+use rand::{thread_rng, Rng};
+use rand::distributions::Alphanumeric;
+use lettre::{SmtpClient, Transport};
+use lettre_email::{Email};
+use lettre::smtp::authentication::{Credentials, Mechanism};
+use lettre::smtp::extension::ClientId;
+use lettre::smtp::ConnectionReuseParameters;
pub struct Settings {
db_url: String,
rate_limit_post_per_second: i32,
rate_limit_register: i32,
rate_limit_register_per_second: i32,
+ email_config: Option<EmailConfig>,
+}
+
+pub struct EmailConfig {
+ smtp_server: String,
+ smtp_login: String,
+ smtp_password: String,
+ smtp_from_address: String,
}
impl Settings {
fn get() -> Self {
dotenv().ok();
+
+ let email_config = if env::var("SMTP_SERVER").is_ok() {
+ Some(EmailConfig {
+ smtp_server: env::var("SMTP_SERVER").expect("SMTP_SERVER must be set"),
+ smtp_login: env::var("SMTP_LOGIN").expect("SMTP_LOGIN must be set"),
+ smtp_password: env::var("SMTP_PASSWORD").expect("SMTP_PASSWORD must be set"),
+ smtp_from_address: env::var("SMTP_FROM_ADDRESS").expect("SMTP_FROM_ADDRESS must be set")
+ })
+ } else {
+ None
+ };
+
Settings {
db_url: env::var("DATABASE_URL").expect("DATABASE_URL must be set"),
hostname: env::var("HOSTNAME").unwrap_or("rrr".to_string()),
.unwrap_or("3600".to_string())
.parse()
.unwrap(),
+ email_config: email_config,
}
}
fn api_endpoint(&self) -> String {
matches.iter().map(|t| &t[3..]).collect()
}
+pub fn generate_random_string() -> String {
+ thread_rng()
+ .sample_iter(&Alphanumeric)
+ .take(30)
+ .collect()
+}
+
+pub fn send_email(subject: &str, to_email: &str, to_username: &str, html: &str) -> Result<(), String> {
+
+ let email_config = Settings::get().email_config.ok_or("no_email_setup")?;
+
+ let email = Email::builder()
+ // .to((to_email, username))
+ .to((to_email, to_username))
+ .from((email_config.smtp_login.to_owned(), email_config.smtp_from_address))
+ .subject(subject)
+ .html(html)
+ .build()
+ .unwrap();
+
+ let mut mailer = SmtpClient::new_simple(&email_config.smtp_server).unwrap()
+ .hello_name(ClientId::Domain("localhost".to_string()))
+ .credentials(Credentials::new(
+ email_config.smtp_login.to_owned(),
+ email_config.smtp_password.to_owned()))
+ .smtp_utf8(true)
+ .authentication_mechanism(Mechanism::Plain)
+ .connection_reuse(ConnectionReuseParameters::ReuseUnlimited)
+ .transport();
+
+ let result = mailer.send(email.into());
+
+ match result {
+ Ok(_) => Ok(()),
+ Err(_) => Err("no_email_setup".to_string()),
+ }
+}
+
#[cfg(test)]
mod tests {
use crate::{extract_usernames, has_slurs, is_email_regex, remove_slurs, Settings};
let expected = vec!["another", "testme"];
assert_eq!(usernames, expected);
}
+
+ // #[test]
+ // fn test_send_email() {
+ // let result = send_email("not a subject", "test_email@gmail.com", "ur user", "<h1>HI there</h1>");
+ // assert!(result.is_ok());
+ // }
}
lazy_static! {
}
}
+table! {
+ password_reset_request (id) {
+ id -> Int4,
+ user_id -> Int4,
+ token_encrypted -> Text,
+ published -> Timestamp,
+ }
+}
+
table! {
post (id) {
id -> Int4,
joinable!(mod_remove_post -> user_ (mod_user_id));
joinable!(mod_sticky_post -> post (post_id));
joinable!(mod_sticky_post -> user_ (mod_user_id));
+joinable!(password_reset_request -> user_ (user_id));
joinable!(post -> community (community_id));
joinable!(post -> user_ (creator_id));
joinable!(post_like -> post (post_id));
joinable!(user_mention -> user_ (recipient_id));
allow_tables_to_appear_in_same_query!(
- category,
- comment,
- comment_like,
- comment_saved,
- community,
- community_follower,
- community_moderator,
- community_user_ban,
- mod_add,
- mod_add_community,
- mod_ban,
- mod_ban_from_community,
- mod_lock_post,
- mod_remove_comment,
- mod_remove_community,
- mod_remove_post,
- mod_sticky_post,
- post,
- post_like,
- post_read,
- post_saved,
- site,
- user_,
- user_ban,
- user_mention,
+ category,
+ comment,
+ comment_like,
+ comment_saved,
+ community,
+ community_follower,
+ community_moderator,
+ community_user_ban,
+ mod_add,
+ mod_add_community,
+ mod_ban,
+ mod_ban_from_community,
+ mod_lock_post,
+ mod_remove_comment,
+ mod_remove_community,
+ mod_remove_post,
+ mod_sticky_post,
+ password_reset_request,
+ post,
+ post_like,
+ post_read,
+ post_saved,
+ site,
+ user_,
+ user_ban,
+ user_mention,
);
let res = Oper::new(user_operation, delete_account).perform()?;
Ok(serde_json::to_string(&res)?)
}
+ UserOperation::PasswordReset => {
+ let password_reset: PasswordReset = serde_json::from_str(data)?;
+ let res = Oper::new(user_operation, password_reset).perform()?;
+ Ok(serde_json::to_string(&res)?)
+ }
+ UserOperation::PasswordChange => {
+ let password_change: PasswordChange = serde_json::from_str(data)?;
+ let res = Oper::new(user_operation, password_change).perform()?;
+ Ok(serde_json::to_string(&res)?)
+ }
}
}
RegisterForm,
LoginResponse,
UserOperation,
+ PasswordResetForm,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { msgOp } from '../utils';
class="form-control"
required
/>
+ <div
+ onClick={linkEvent(this, this.handlePasswordReset)}
+ class="pointer d-inline-block float-right text-muted small font-weight-bold"
+ >
+ <T i18nKey="forgot_password">#</T>
+ </div>
</div>
</div>
<div class="form-group row">
i.setState(i.state);
}
+ handlePasswordReset(i: Login) {
+ let resetForm: PasswordResetForm = {
+ email: i.state.loginForm.username_or_email,
+ };
+ WebSocketService.Instance.passwordReset(resetForm);
+ }
+
parseMessage(msg: any) {
let op: UserOperation = msgOp(msg);
if (msg.error) {
let res: LoginResponse = msg;
UserService.Instance.login(res);
this.props.history.push('/communities');
+ } else if (op == UserOperation.PasswordReset) {
+ alert(i18n.t('reset_password_mail_sent'));
}
}
}
interface NavbarState {
isLoggedIn: boolean;
expanded: boolean;
- expandUserDropdown: boolean;
replies: Array<Comment>;
mentions: Array<Comment>;
fetchCount: number;
replies: [],
mentions: [],
expanded: false,
- expandUserDropdown: false,
siteName: undefined,
};
constructor(props: any, context: any) {
super(props, context);
this.state = this.emptyState;
- this.handleOverviewClick = this.handleOverviewClick.bind(this);
this.keepFetchingUnreads();
<ul class="navbar-nav ml-auto mr-2">
{this.state.isLoggedIn ? (
<>
- {
- <li className="nav-item">
- <Link class="nav-link" to="/inbox">
- <svg class="icon">
- <use xlinkHref="#icon-mail"></use>
- </svg>
- {this.state.unreadCount > 0 && (
- <span class="ml-1 badge badge-light">
- {this.state.unreadCount}
- </span>
- )}
- </Link>
- </li>
- }
- <li
- className={`nav-item dropdown ${this.state
- .expandUserDropdown && 'show'}`}
- >
- <a
- class="pointer nav-link dropdown-toggle"
- onClick={linkEvent(this, this.expandUserDropdown)}
- role="button"
+ <li className="nav-item">
+ <Link class="nav-link" to="/inbox">
+ <svg class="icon">
+ <use xlinkHref="#icon-mail"></use>
+ </svg>
+ {this.state.unreadCount > 0 && (
+ <span class="ml-1 badge badge-light">
+ {this.state.unreadCount}
+ </span>
+ )}
+ </Link>
+ </li>
+ <li className="nav-item">
+ <Link
+ class="nav-link"
+ to={`/u/${UserService.Instance.user.username}`}
>
{UserService.Instance.user.username}
- </a>
- <div
- className={`dropdown-menu dropdown-menu-right ${this.state
- .expandUserDropdown && 'show'}`}
- >
- <a
- role="button"
- class="dropdown-item pointer"
- onClick={linkEvent(this, this.handleOverviewClick)}
- >
- <T i18nKey="overview">#</T>
- </a>
- <a
- role="button"
- class="dropdown-item pointer"
- onClick={linkEvent(this, this.handleLogoutClick)}
- >
- <T i18nKey="logout">#</T>
- </a>
- </div>
+ </Link>
</li>
</>
) : (
);
}
- expandUserDropdown(i: Navbar) {
- i.state.expandUserDropdown = !i.state.expandUserDropdown;
- i.setState(i.state);
- }
-
- handleLogoutClick(i: Navbar) {
- i.state.expandUserDropdown = false;
- UserService.Instance.logout();
- i.context.router.history.push('/');
- }
-
- handleOverviewClick(i: Navbar) {
- i.state.expandUserDropdown = false;
- i.setState(i.state);
- let userPage = `/u/${UserService.Instance.user.username}`;
- i.context.router.history.push(userPage);
- }
-
expandNavbar(i: Navbar) {
i.state.expanded = !i.state.expanded;
i.setState(i.state);
</tr>
</table>
</div>
+ {this.isCurrentUser && (
+ <button
+ class="btn btn-block btn-secondary mt-3"
+ onClick={linkEvent(this, this.handleLogoutClick)}
+ >
+ <T i18nKey="logout">#</T>
+ </button>
+ )}
</div>
</div>
</div>
i.setState(i.state);
}
+ handleLogoutClick(i: User) {
+ UserService.Instance.logout();
+ i.context.router.history.push('/');
+ }
+
handleDeleteAccount(i: User, event: any) {
event.preventDefault();
i.state.deleteAccountLoading = true;
TransferCommunity,
TransferSite,
DeleteAccount,
+ PasswordReset,
+ PasswordChange,
}
export enum CommentSortType {
export interface DeleteAccountForm {
password: string;
}
+
+export interface PasswordResetForm {
+ email: string;
+}
+
+export interface PasswordResetResponse {
+ op: string;
+}
+
+export interface PasswordChangeForm {
+ token: string;
+ password: string;
+ password_verify: string;
+}
SearchForm,
UserSettingsForm,
DeleteAccountForm,
+ PasswordResetForm,
} from '../interfaces';
import { webSocket } from 'rxjs/webSocket';
import { Subject } from 'rxjs';
this.subject.next(this.wsSendWrapper(UserOperation.DeleteAccount, form));
}
+ public passwordReset(form: PasswordResetForm) {
+ this.subject.next(this.wsSendWrapper(UserOperation.PasswordReset, form));
+ }
+
private wsSendWrapper(op: UserOperation, data: any) {
let send = { op: UserOperation[op], data: data };
console.log(send);
unread_messages: 'Unread Messages',
password: 'Password',
verify_password: 'Verify Password',
+ forgot_password: 'forgot password',
+ reset_password_mail_sent: 'Sent an Email to reset your password.',
+ no_email_setup: "This server hasn't correctly set up email.",
email: 'Email',
optional: 'Optional',
expires: 'Expires',