Password reset (#448)
* Password reset * Various improvements and fixes for password reset - Reorganize src/mail.rs to make it cleaner - add a build_mail function - only make the requests invalid after 2 hours - avoid infintely-growing list of requests by deleting them once completed, or after 24 hours - avoid sending many requests for the same user - validate the password reset form * Avoid locking so many times Fix durations * Remove old requests even if the current one is not valid * Remove unused feature * Also remove the custom_derive and plugin features while we are at it * Forgot a 0 è_é * Avoid panicking while owning a request lock * Use master branch of lettre so that we can build with the latest OpenSSL * Fix the debug mailer
This commit is contained in:
parent
e28371bbe4
commit
a2b9d7ec44
|
@ -115,6 +115,11 @@ name = "ascii"
|
|||
version = "0.9.1"
|
||||
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 = "askama_escape"
|
||||
version = "0.1.0"
|
||||
|
@ -292,6 +297,11 @@ dependencies = [
|
|||
"safemem 0.2.0 (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 = "byte-tools"
|
||||
version = "0.2.0"
|
||||
|
@ -744,6 +754,20 @@ name = "either"
|
|||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "email"
|
||||
version = "0.0.19"
|
||||
source = "git+https://github.com/lettre/rust-email#3086d7bcda2c3b3fa4b1297cba216151ce4a3efc"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (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.2.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"
|
||||
|
@ -852,6 +876,14 @@ name = "fake-simd"
|
|||
version = "0.1.2"
|
||||
source = "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 = "filetime"
|
||||
version = "0.2.4"
|
||||
|
@ -1090,6 +1122,15 @@ name = "hex"
|
|||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.22.5"
|
||||
|
@ -1288,6 +1329,40 @@ name = "lazycell"
|
|||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lettre"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49#c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.5 (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.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lettre_email"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49#c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"email 0.0.19 (git+https://github.com/lettre/rust-email)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)",
|
||||
"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.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "levenshtein_automata"
|
||||
version = "0.1.1"
|
||||
|
@ -1849,6 +1924,8 @@ dependencies = [
|
|||
"gettext-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"guid-create 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)",
|
||||
"lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)",
|
||||
"multipart 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plume-api 0.2.0",
|
||||
|
@ -3366,6 +3443,14 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winutil"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
|
@ -3400,6 +3485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
|
||||
"checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335"
|
||||
"checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
|
||||
"checksum askama_escape 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "719b48039ffac1564f67d70162109ba9341125cee0096a540e478355b3c724a7"
|
||||
"checksum atom_syndication 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a9a7ab83635ff7a3b04856f4ad95324dccc9b947ab1e790fc5c769ee6d6f60c"
|
||||
"checksum atomicwrites 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3420b33cdefd3feb223dddc23739fc05cc034eb0f2be792c763e3d89e1eb6e3"
|
||||
|
@ -3421,6 +3507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"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 buf_redux 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f25c67abbf523ff8457771622fb731ac4a2391439de33bc60febcdee1749c9"
|
||||
"checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8"
|
||||
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
|
||||
"checksum bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b92204551573580e078dc80017f36a213eb77a0450e4ddd8cfa0f3f2d1f0178f"
|
||||
"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304"
|
||||
|
@ -3475,6 +3562,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
|
||||
"checksum either 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a39bffec1e2015c5d8a6773cb0cf48d0d758c842398f624c34969071f5499ea7"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum email 0.0.19 (git+https://github.com/lettre/rust-email)" = "<none>"
|
||||
"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"
|
||||
|
@ -3488,6 +3576,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"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 fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
"checksum fast_chemail 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4"
|
||||
"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
|
||||
"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"
|
||||
|
@ -3516,6 +3605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
"checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e"
|
||||
"checksum html5ever 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c213fa6a618dc1da552f54f85cba74b05d8e883c92ec4e89067736938084c26e"
|
||||
"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
|
||||
"checksum http 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1a10e5b573b9a0146545010f50772b9e8b1dd0a256564cc4307694c68832a2f5"
|
||||
|
@ -3538,6 +3628,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)" = "<none>"
|
||||
"checksum lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)" = "<none>"
|
||||
"checksum levenshtein_automata 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73a004f877f468548d8d0ac4977456a249d8fabbdb8416c36db163dfc8f2e8ca"
|
||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||
"checksum libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "bff3ac7d6f23730d3b533c35ed75eef638167634476a499feef16c428d74b57b"
|
||||
|
@ -3753,6 +3845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48"
|
||||
"checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
|
||||
|
|
|
@ -17,6 +17,8 @@ gettext-macros = "0.3"
|
|||
gettext-utils = "0.1"
|
||||
guid-create = "0.1"
|
||||
heck = "0.3.0"
|
||||
lettre = { git = "https://github.com/lettre/lettre", rev = "c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49" }
|
||||
lettre_email = { git = "https://github.com/lettre/lettre", rev = "c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49" }
|
||||
num_cpus = "1.0"
|
||||
rocket = "0.4.0"
|
||||
rocket_contrib = { version = "0.4.0", features = ["json"] }
|
||||
|
@ -73,6 +75,7 @@ rsass = "0.9"
|
|||
default = ["postgres"]
|
||||
postgres = ["plume-models/postgres", "diesel/postgres"]
|
||||
sqlite = ["plume-models/sqlite", "diesel/sqlite"]
|
||||
debug-mailer = []
|
||||
|
||||
[workspace]
|
||||
members = ["plume-api", "plume-cli", "plume-models", "plume-common", "plume-front"]
|
||||
|
|
|
@ -70,6 +70,22 @@ msgstr "تعديل {0}"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "يجب عليك تسجيل الدخول قصد الإعجاب بالمنشور"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "كلمة السر"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr "لا يمكن ترك خانة الكلمة السرية فارغة"
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "يجب عليك أولا تسجيل الدخول للوصول إلى لوح التحكم"
|
||||
|
||||
|
@ -468,6 +484,36 @@ msgstr "الانتقال إلى معرضك"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "كلمة السر"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "الإعدادات"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "تحديث الحساب"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "البريد الالكتروني"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr "تسجيل الدخول"
|
||||
|
||||
|
@ -796,9 +842,6 @@ msgstr "استخدمها كصورة رمزية"
|
|||
#~ msgid "We need an email or a username to identify you"
|
||||
#~ msgstr "نحن بحاجة إلى عنوان بريد إلكتروني أو اسم مستخدم للتعرف عليك"
|
||||
|
||||
#~ msgid "Your password can't be empty"
|
||||
#~ msgstr "لا يمكن ترك خانة الكلمة السرية فارغة"
|
||||
|
||||
#~ msgid "Passwords are not matching"
|
||||
#~ msgstr "الكلمات السرية غير متشابهة"
|
||||
|
||||
|
|
|
@ -74,6 +74,22 @@ msgstr "Bearbeiten"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Du musst eingeloggt sein, um deine Benachrichtigungen zu sehen"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Passwort"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Du musst eingeloggt sein, um dein Dashboard zu sehen"
|
||||
|
@ -482,6 +498,36 @@ msgstr "Zu deiner Gallerie"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Konfiguration"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Account aktualisieren"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "E-Mail"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -78,6 +78,22 @@ msgstr ""
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:147
|
||||
msgid "Password reset"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:131
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr ""
|
||||
|
@ -459,6 +475,35 @@ msgstr ""
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:144
|
||||
msgid "New password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:144
|
||||
msgid "Confirmation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update password"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:144
|
||||
msgid "E-mail"
|
||||
msgstr ""
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -76,6 +76,22 @@ msgstr "Modifier {0}"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Vous devez vous connecter pour voir vos notifications"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Vous devez vous connecter pour accéder à votre tableau de bord"
|
||||
|
@ -477,6 +493,36 @@ msgstr "Aucun résultat pour votre recherche"
|
|||
msgid "No more result for your query"
|
||||
msgstr "Plus de résultats pour votre recherche"
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Configuration"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Mettre à jour mes informations"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Adresse électronique"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -73,6 +73,22 @@ msgstr "Editar"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Debe estar conectada para ver as súas notificacións"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Contrasinal"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Debe estar conectada para acceder ao seu taboleiro"
|
||||
|
@ -477,6 +493,36 @@ msgstr "Ir a súa galería"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Contrasinal"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Axustes"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Actualizar conta"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Correo-e"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -73,6 +73,22 @@ msgstr "Modifica"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Devi effettuare l'accesso per vedere le tue notifiche"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Password"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Devi effettuare l'accesso per accedere al tuo pannello"
|
||||
|
@ -480,6 +496,36 @@ msgstr "Vai alla tua galleria"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Password"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Configurazione"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Aggiorna account"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Email"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -71,6 +71,22 @@ msgstr "編集"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "投稿をいいねするにはログインする必要があります"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "パスワード"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr "パスワードは空にできません"
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "ダッシュボードにアクセスするにはログインする必要があります"
|
||||
|
||||
|
@ -473,6 +489,36 @@ msgstr "ギャラリーを参照"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "パスワード"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "設定"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "アカウントをアップデート"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "メールアドレス"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr "ログイン"
|
||||
|
||||
|
@ -790,9 +836,6 @@ msgstr "アバターとして使う"
|
|||
#~ msgid "We need an email or a username to identify you"
|
||||
#~ msgstr "あなたを識別するために、メールアドレスかユーザー名が必要です"
|
||||
|
||||
#~ msgid "Your password can't be empty"
|
||||
#~ msgstr "パスワードは空にできません"
|
||||
|
||||
#~ msgid "Passwords are not matching"
|
||||
#~ msgstr "パスワードが一致しません"
|
||||
|
||||
|
|
|
@ -76,6 +76,22 @@ msgstr "Kommentér \"{0}\""
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Du må være logget inn for å se meldingene dine"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Passord"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Du må være logget inn for å redigere profilen din"
|
||||
|
@ -505,6 +521,36 @@ msgstr ""
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Passord"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Oppsett"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Oppdater konto"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Epost"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr "Logg inn"
|
||||
|
||||
|
|
|
@ -63,6 +63,22 @@ msgstr "Edytuj {0}"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Musisz się zalogować, aby udostępnić wpis"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Hasło"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Musisz się zalogować, aby uzyskać dostęp do panelu"
|
||||
|
||||
|
@ -447,6 +463,36 @@ msgstr "Brak wyników dla tego kryterium"
|
|||
msgid "No more result for your query"
|
||||
msgstr "Nie ma więcej wyników pasujących do tych kryteriów"
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Hasło"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Konfiguracja"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Aktualizuj konto"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Adres e-mail"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr "Zaloguj się"
|
||||
|
||||
|
|
|
@ -76,6 +76,22 @@ msgstr ""
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:161
|
||||
msgid "Password reset"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:162
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:222
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:224
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:131
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr ""
|
||||
|
@ -453,6 +469,33 @@ msgstr ""
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:144
|
||||
msgid "New password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:144
|
||||
msgid "Confirmation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update password"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid "We sent a mail to the address you gave us, with a link to reset your password."
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:144
|
||||
msgid "E-mail"
|
||||
msgstr ""
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -69,6 +69,22 @@ msgstr "Mudar {0}"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Você precisa estar logado para gostar de um post"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Senha"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr "Sua senha não pode estar vazia"
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Você precisa estar autenticado para acessar seu painel de controle"
|
||||
|
||||
|
@ -468,6 +484,36 @@ msgstr "Ir para a sua galeria"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Senha"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Configuração"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Atualizar conta"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Email"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr "Entrar"
|
||||
|
||||
|
@ -771,9 +817,6 @@ msgstr "Utilizar como avatar"
|
|||
#~ msgstr ""
|
||||
#~ "Precisamos de um endereço de e-mail ou nome de usuário para identificá-lo"
|
||||
|
||||
#~ msgid "Your password can't be empty"
|
||||
#~ msgstr "Sua senha não pode estar vazia"
|
||||
|
||||
#~ msgid "Passwords are not matching"
|
||||
#~ msgstr "As senhas não correspondem"
|
||||
|
||||
|
|
|
@ -75,6 +75,22 @@ msgstr "Редактировать"
|
|||
msgid "You need to be logged in order to reshare a post"
|
||||
msgstr "Вы должны войти чтобы просматривать ваши уведомления"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Password reset"
|
||||
msgstr "Пароль"
|
||||
|
||||
# src/routes/session.rs:156
|
||||
msgid "Here is the link to reset your password: {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:199
|
||||
msgid "Your password was successfully reset."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/session.rs:214
|
||||
msgid "Sorry, but the link expired. Try again"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "You need to be logged in order to access your dashboard"
|
||||
msgstr "Вы должны войти чтобы получить доступ к вашей панели управления"
|
||||
|
@ -484,6 +500,36 @@ msgstr "Перейти в вашу галерею"
|
|||
msgid "No more result for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "New password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Confirmation"
|
||||
msgstr "Конфигурация"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Update password"
|
||||
msgstr "Обновить аккаунт"
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"We sent a mail to the address you gave us, with a link to reset your "
|
||||
"password."
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "E-mail"
|
||||
msgstr "Электронная почта"
|
||||
|
||||
msgid "Send reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
use lettre_email::Email;
|
||||
use std::env;
|
||||
|
||||
pub use self::mailer::*;
|
||||
|
||||
#[cfg(feature = "debug-mailer")]
|
||||
mod mailer {
|
||||
use lettre::{Transport, SendableEmail};
|
||||
use std::{io::Read};
|
||||
|
||||
pub struct DebugTransport;
|
||||
|
||||
impl<'a> Transport<'a> for DebugTransport {
|
||||
type Result = Result<(), ()>;
|
||||
|
||||
fn send(&mut self, email: SendableEmail) -> Self::Result {
|
||||
println!(
|
||||
"{}: from=<{}> to=<{:?}>\n{:#?}",
|
||||
email.message_id().to_string(),
|
||||
email.envelope().from().map(ToString::to_string).unwrap_or_default(),
|
||||
email.envelope().to().to_vec(),
|
||||
{
|
||||
let mut message = String::new();
|
||||
email.message().read_to_string(&mut message).map_err(|_| ())?;
|
||||
message
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Mailer = Option<DebugTransport>;
|
||||
|
||||
pub fn init() -> Mailer {
|
||||
Some(DebugTransport)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug-mailer"))]
|
||||
mod mailer {
|
||||
use lettre::{
|
||||
SmtpTransport,
|
||||
SmtpClient,
|
||||
smtp::{
|
||||
authentication::{Credentials, Mechanism},
|
||||
extension::ClientId,
|
||||
ConnectionReuseParameters,
|
||||
},
|
||||
};
|
||||
use std::env;
|
||||
|
||||
pub type Mailer = Option<SmtpTransport>;
|
||||
|
||||
pub fn init() -> Mailer {
|
||||
let server = env::var("MAIL_SERVER").ok()?;
|
||||
let helo_name = env::var("MAIL_HELO_NAME").unwrap_or_else(|_| "localhost".to_owned());
|
||||
let username = env::var("MAIL_USER").ok()?;
|
||||
let password = env::var("MAIL_PASSWORD").ok()?;
|
||||
let mail = SmtpClient::new_simple(&server).unwrap()
|
||||
.hello_name(ClientId::Domain(helo_name))
|
||||
.credentials(Credentials::new(username, password))
|
||||
.smtp_utf8(true)
|
||||
.authentication_mechanism(Mechanism::Plain)
|
||||
.connection_reuse(ConnectionReuseParameters::NoReuse)
|
||||
.transport();
|
||||
Some(mail)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_mail(dest: String, subject: String, body: String) -> Option<Email> {
|
||||
Email::builder()
|
||||
.from(env::var("MAIL_ADDRESS")
|
||||
.or_else(|_| Ok(format!("{}@{}", env::var("MAIL_USER")?, env::var("MAIL_SERVER")?)) as Result<_, env::VarError>)
|
||||
.expect("Mail server is not correctly configured"))
|
||||
.to(dest)
|
||||
.subject(subject)
|
||||
.text(body)
|
||||
.build()
|
||||
.ok()
|
||||
}
|
19
src/main.rs
19
src/main.rs
|
@ -1,4 +1,4 @@
|
|||
#![feature(custom_derive, plugin, decl_macro, proc_macro_hygiene)]
|
||||
#![feature(decl_macro, proc_macro_hygiene)]
|
||||
|
||||
extern crate activitypub;
|
||||
extern crate askama_escape;
|
||||
|
@ -15,6 +15,8 @@ extern crate gettext_macros;
|
|||
extern crate gettext_utils;
|
||||
extern crate guid_create;
|
||||
extern crate heck;
|
||||
extern crate lettre;
|
||||
extern crate lettre_email;
|
||||
extern crate multipart;
|
||||
extern crate num_cpus;
|
||||
extern crate plume_api;
|
||||
|
@ -51,13 +53,14 @@ use plume_models::{
|
|||
use scheduled_thread_pool::ScheduledThreadPool;
|
||||
use std::env;
|
||||
use std::process::exit;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
init_i18n!("plume", ar, de, en, es, fr, gl, it, ja, nb, pl, pt, ru);
|
||||
|
||||
mod api;
|
||||
mod inbox;
|
||||
mod mail;
|
||||
#[macro_use]
|
||||
mod template_utils;
|
||||
mod routes;
|
||||
|
@ -117,6 +120,12 @@ Then try to restart Plume.
|
|||
.limit("forms", form_size * 1024)
|
||||
.limit("json", activity_size * 1024));
|
||||
|
||||
let mail = mail::init();
|
||||
if mail.is_none() && config.environment.is_prod() {
|
||||
println!("Warning: the email server is not configured (or not completely).");
|
||||
println!("Please refer to the documentation to see how to configure it.");
|
||||
}
|
||||
|
||||
rocket::custom(config)
|
||||
.mount("/", routes![
|
||||
routes::blogs::details,
|
||||
|
@ -177,6 +186,10 @@ Then try to restart Plume.
|
|||
routes::session::new,
|
||||
routes::session::create,
|
||||
routes::session::delete,
|
||||
routes::session::password_reset_request_form,
|
||||
routes::session::password_reset_request,
|
||||
routes::session::password_reset_form,
|
||||
routes::session::password_reset,
|
||||
|
||||
routes::static_files,
|
||||
|
||||
|
@ -222,6 +235,8 @@ Then try to restart Plume.
|
|||
routes::errors::unprocessable_entity,
|
||||
routes::errors::server_error
|
||||
])
|
||||
.manage(Arc::new(Mutex::new(mail)))
|
||||
.manage::<Arc<Mutex<Vec<routes::session::ResetRequest>>>>(Arc::new(Mutex::new(vec![])))
|
||||
.manage(dbpool)
|
||||
.manage(workpool)
|
||||
.manage(searcher)
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
use lettre::Transport;
|
||||
use rocket::{
|
||||
State,
|
||||
http::{Cookie, Cookies, SameSite, uri::Uri},
|
||||
response::Redirect,
|
||||
request::{LenientForm,FlashMessage}
|
||||
request::{LenientForm, FlashMessage, Form}
|
||||
};
|
||||
use rocket::http::ext::IntoOwned;
|
||||
use rocket_i18n::I18n;
|
||||
use std::borrow::Cow;
|
||||
use std::{borrow::Cow, sync::{Arc, Mutex}, time::Instant};
|
||||
use validator::{Validate, ValidationError, ValidationErrors};
|
||||
use template_utils::Ructe;
|
||||
|
||||
use plume_models::{
|
||||
BASE_URL, Error,
|
||||
db_conn::DbConn,
|
||||
users::{User, AUTH_COOKIE}
|
||||
};
|
||||
|
||||
use mail::{build_mail, Mailer};
|
||||
use routes::errors::ErrorPage;
|
||||
|
||||
#[get("/login?<m>")]
|
||||
pub fn new(user: Option<User>, conn: DbConn, m: Option<String>, intl: I18n) -> Ructe {
|
||||
|
@ -76,7 +80,7 @@ pub fn create(conn: DbConn, form: LenientForm<LoginForm>, flash: Option<FlashMes
|
|||
|
||||
let uri = Uri::parse(&destination)
|
||||
.map(|x| x.into_owned())
|
||||
.map_err(|_| render!(session::login(
|
||||
.map_err(|_| render!(session::login(
|
||||
&(&*conn, &intl.catalog, None),
|
||||
None,
|
||||
&*form,
|
||||
|
@ -101,3 +105,140 @@ pub fn delete(mut cookies: Cookies) -> Redirect {
|
|||
}
|
||||
Redirect::to("/")
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ResetRequest {
|
||||
pub mail: String,
|
||||
pub id: String,
|
||||
pub creation_date: Instant,
|
||||
}
|
||||
|
||||
impl PartialEq for ResetRequest {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/password-reset")]
|
||||
pub fn password_reset_request_form(conn: DbConn, intl: I18n) -> Ructe {
|
||||
render!(session::password_reset_request(
|
||||
&(&*conn, &intl.catalog, None),
|
||||
&ResetForm::default(),
|
||||
ValidationErrors::default()
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(FromForm, Validate, Default)]
|
||||
pub struct ResetForm {
|
||||
#[validate(email)]
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
#[post("/password-reset", data = "<form>")]
|
||||
pub fn password_reset_request(
|
||||
conn: DbConn,
|
||||
intl: I18n,
|
||||
mail: State<Arc<Mutex<Mailer>>>,
|
||||
form: Form<ResetForm>,
|
||||
requests: State<Arc<Mutex<Vec<ResetRequest>>>>
|
||||
) -> Ructe {
|
||||
let mut requests = requests.lock().unwrap();
|
||||
// Remove outdated requests (more than 1 day old) to avoid the list to grow too much
|
||||
requests.retain(|r| r.creation_date.elapsed().as_secs() < 24 * 60 * 60);
|
||||
|
||||
if User::find_by_email(&*conn, &form.email).is_ok() && !requests.iter().any(|x| x.mail == form.email.clone()) {
|
||||
let id = plume_common::utils::random_hex();
|
||||
|
||||
requests.push(ResetRequest {
|
||||
mail: form.email.clone(),
|
||||
id: id.clone(),
|
||||
creation_date: Instant::now(),
|
||||
});
|
||||
|
||||
let link = format!("https://{}/password-reset/{}", *BASE_URL, id);
|
||||
if let Some(message) = build_mail(
|
||||
form.email.clone(),
|
||||
i18n!(intl.catalog, "Password reset"),
|
||||
i18n!(intl.catalog, "Here is the link to reset your password: {0}"; link)
|
||||
) {
|
||||
match *mail.lock().unwrap() {
|
||||
Some(ref mut mail) => { mail.send(message.into()).map_err(|_| eprintln!("Couldn't send password reset mail")).ok(); }
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
render!(session::password_reset_request_ok(
|
||||
&(&*conn, &intl.catalog, None)
|
||||
))
|
||||
}
|
||||
|
||||
#[get("/password-reset/<token>")]
|
||||
pub fn password_reset_form(conn: DbConn, intl: I18n, token: String, requests: State<Arc<Mutex<Vec<ResetRequest>>>>) -> Result<Ructe, ErrorPage> {
|
||||
requests.lock().unwrap().iter().find(|x| x.id == token.clone()).ok_or(Error::NotFound)?;
|
||||
Ok(render!(session::password_reset(
|
||||
&(&*conn, &intl.catalog, None),
|
||||
&NewPasswordForm::default(),
|
||||
ValidationErrors::default()
|
||||
)))
|
||||
}
|
||||
|
||||
#[derive(FromForm, Default, Validate)]
|
||||
#[validate(
|
||||
schema(
|
||||
function = "passwords_match",
|
||||
skip_on_field_errors = "false",
|
||||
message = "Passwords are not matching"
|
||||
)
|
||||
)]
|
||||
pub struct NewPasswordForm {
|
||||
pub password: String,
|
||||
pub password_confirmation: String,
|
||||
}
|
||||
|
||||
fn passwords_match(form: &NewPasswordForm) -> Result<(), ValidationError> {
|
||||
if form.password != form.password_confirmation {
|
||||
Err(ValidationError::new("password_match"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/password-reset/<token>", data = "<form>")]
|
||||
pub fn password_reset(
|
||||
conn: DbConn,
|
||||
intl: I18n,
|
||||
token: String,
|
||||
requests: State<Arc<Mutex<Vec<ResetRequest>>>>,
|
||||
form: Form<NewPasswordForm>
|
||||
) -> Result<Redirect, Ructe> {
|
||||
form.validate()
|
||||
.and_then(|_| {
|
||||
let mut requests = requests.lock().unwrap();
|
||||
let req = requests.iter().find(|x| x.id == token.clone()).ok_or(to_validation(0))?.clone();
|
||||
if req.creation_date.elapsed().as_secs() < 60 * 60 * 2 { // Reset link is only valid for 2 hours
|
||||
requests.retain(|r| *r != req);
|
||||
let user = User::find_by_email(&*conn, &req.mail).map_err(to_validation)?;
|
||||
user.reset_password(&*conn, &form.password).ok();
|
||||
Ok(Redirect::to(uri!(new: m = i18n!(intl.catalog, "Your password was successfully reset."))))
|
||||
} else {
|
||||
Ok(Redirect::to(uri!(new: m = i18n!(intl.catalog, "Sorry, but the link expired. Try again"))))
|
||||
}
|
||||
})
|
||||
.map_err(|err| {
|
||||
render!(session::password_reset(
|
||||
&(&*conn, &intl.catalog, None),
|
||||
&form,
|
||||
err
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn to_validation<T>(_: T) -> ValidationErrors {
|
||||
let mut errors = ValidationErrors::new();
|
||||
errors.add("", ValidationError {
|
||||
code: Cow::from("server_error"),
|
||||
message: Some(Cow::from("An unknown error occured")),
|
||||
params: std::collections::HashMap::new()
|
||||
});
|
||||
errors
|
||||
}
|
||||
|
|
|
@ -16,4 +16,5 @@
|
|||
@input!(ctx.1, password (password), "Password", form, errors, "minlenght=\"1\"")
|
||||
<input type="submit" value="@i18n!(ctx.1, "Login")" />
|
||||
</form>
|
||||
<a href="@uri!(session::password_reset_request_form)">Forgot your password?</a>
|
||||
})
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
@use template_utils::*;
|
||||
@use templates::base;
|
||||
@use routes::session::NewPasswordForm;
|
||||
@use validator::ValidationErrors;
|
||||
|
||||
@(ctx: BaseContext, form: &NewPasswordForm, errors: ValidationErrors)
|
||||
|
||||
@:base(ctx, i18n!(ctx.1, "Reset your password"), {}, {}, {
|
||||
<h1>@i18n!(ctx.1, "Reset your password")</h1>
|
||||
|
||||
<form method="POST">
|
||||
@input!(ctx.1, password (password), "New password", form, errors.clone(), "minlenght=\"8\"")
|
||||
@input!(ctx.1, password_confirmation (password), "Confirmation", form, errors.clone(), "minlenght=\"8\"")
|
||||
<input type="submit" value="@i18n!(ctx.1, "Update password")" />
|
||||
</form>
|
||||
})
|
|
@ -0,0 +1,15 @@
|
|||
@use template_utils::*;
|
||||
@use templates::base;
|
||||
@use routes::session::ResetForm;
|
||||
@use validator::ValidationErrors;
|
||||
|
||||
@(ctx: BaseContext, form: &ResetForm, errors: ValidationErrors)
|
||||
|
||||
@:base(ctx, i18n!(ctx.1, "Reset your password"), {}, {}, {
|
||||
<h1>@i18n!(ctx.1, "Reset your password")</h1>
|
||||
|
||||
<form method="POST">
|
||||
@input!(ctx.1, email (email), "E-mail", form, errors.clone(), "minlenght=\"1\"")
|
||||
<input type="submit" value="@i18n!(ctx.1, "Send reset link")" />
|
||||
</form>
|
||||
})
|
|
@ -0,0 +1,9 @@
|
|||
@use template_utils::*;
|
||||
@use templates::base;
|
||||
|
||||
@(ctx: BaseContext)
|
||||
|
||||
@:base(ctx, i18n!(ctx.1, "Password reset"), {}, {}, {
|
||||
<h1>@i18n!(ctx.1, "Check your inbox!")</h1>
|
||||
<p>@i18n!(ctx.1, "We sent a mail to the address you gave us, with a link to reset your password.")</p>
|
||||
})
|
Loading…
Reference in New Issue