From feb9f16bc9f14a0034d3a930e90f15301de60dbc Mon Sep 17 00:00:00 2001 From: Philippe Loctaux
Date: Sat, 22 Apr 2023 01:27:24 +0200
Subject: [PATCH] forgot password: send emails
---
Cargo.lock | 269 +++++++++++++++++-
Dockerfile | 1 +
crates/email/Cargo.toml | 24 ++
crates/email/readme.md | 36 +++
crates/email/src/lib.rs | 151 ++++++++++
.../email/templates/password-reset.mjml.tera | 50 ++++
crates/ezidam/Cargo.toml | 1 +
crates/ezidam/Rocket.toml | 6 +
crates/ezidam/src/main.rs | 28 +-
.../ezidam/src/routes/root/forgot_password.rs | 128 ++++++++-
10 files changed, 676 insertions(+), 18 deletions(-)
create mode 100644 crates/email/Cargo.toml
create mode 100644 crates/email/readme.md
create mode 100644 crates/email/src/lib.rs
create mode 100644 crates/email/templates/password-reset.mjml.tera
diff --git a/Cargo.lock b/Cargo.lock
index d2d680d..2abe08f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,16 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "Inflector"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
+dependencies = [
+ "lazy_static",
+ "regex",
+]
+
[[package]]
name = "ahash"
version = "0.7.6"
@@ -447,8 +457,18 @@ version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
- "darling_core",
- "darling_macro",
+ "darling_core 0.13.4",
+ "darling_macro 0.13.4",
+]
+
+[[package]]
+name = "darling"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
+dependencies = [
+ "darling_core 0.14.4",
+ "darling_macro 0.14.4",
]
[[package]]
@@ -465,13 +485,38 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "darling_core"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.109",
+]
+
[[package]]
name = "darling_macro"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
- "darling_core",
+ "darling_core 0.13.4",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
+dependencies = [
+ "darling_core 0.14.4",
"quote",
"syn 1.0.109",
]
@@ -608,6 +653,27 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "email"
+version = "0.0.0"
+dependencies = [
+ "lettre",
+ "mrml",
+ "serde",
+ "tera",
+ "thiserror",
+]
+
+[[package]]
+name = "email-encoding"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75"
+dependencies = [
+ "base64 0.21.0",
+ "memchr",
+]
+
[[package]]
name = "email_address"
version = "0.2.4"
@@ -668,6 +734,7 @@ dependencies = [
"base64 0.21.0",
"chrono-tz 0.8.2",
"database_pool",
+ "email",
"email_address",
"erased-serde",
"futures",
@@ -1056,6 +1123,17 @@ dependencies = [
"digest",
]
+[[package]]
+name = "hostname"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
+dependencies = [
+ "libc",
+ "match_cfg",
+ "winapi",
+]
+
[[package]]
name = "http"
version = "0.2.9"
@@ -1355,6 +1433,34 @@ dependencies = [
"spin 0.5.2",
]
+[[package]]
+name = "lettre"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76bd09637ae3ec7bd605b8e135e757980b3968430ff2b1a4a94fb7769e50166d"
+dependencies = [
+ "async-trait",
+ "base64 0.21.0",
+ "email-encoding",
+ "email_address",
+ "fastrand",
+ "futures-io",
+ "futures-util",
+ "hostname",
+ "httpdate",
+ "idna",
+ "mime",
+ "nom",
+ "once_cell",
+ "quoted_printable",
+ "rustls 0.21.0",
+ "rustls-pemfile",
+ "socket2",
+ "tokio",
+ "tokio-rustls 0.24.0",
+ "webpki-roots 0.23.0",
+]
+
[[package]]
name = "libc"
version = "0.2.140"
@@ -1427,6 +1533,12 @@ dependencies = [
"tracing-subscriber",
]
+[[package]]
+name = "match_cfg"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
+
[[package]]
name = "matchers"
version = "0.1.0"
@@ -1466,6 +1578,88 @@ dependencies = [
"windows-sys 0.45.0",
]
+[[package]]
+name = "mrml"
+version = "2.0.0-rc2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b65039434eb297dfdd343ea1e4f28e95366ce6d957de07a24a940d5e760ede1"
+dependencies = [
+ "indexmap",
+ "mrml-json-macros",
+ "mrml-macros",
+ "mrml-parse-macros",
+ "mrml-print-macros",
+ "rand",
+ "rustc-hash",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "xmlparser",
+]
+
+[[package]]
+name = "mrml-common-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "646bbe56cd666665355ddc095162c603c64511e897bd5033376abdcf8b9be623"
+dependencies = [
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "mrml-json-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f08de794f5dae4be523ef4ae7b35c53e70d6b37fe3995db2e2d0d2dec784677"
+dependencies = [
+ "Inflector",
+ "darling 0.14.4",
+ "mrml-common-macros",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "mrml-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c2c5bffc248ce37d7c1b55389cf4ccae1a7647e4ed295684906c9ab0cd762bd"
+dependencies = [
+ "Inflector",
+ "mrml-common-macros",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "mrml-parse-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "012179ed2e5f76915544bc78e8aeed10f49fdc06f60f1250c7a993568569c7c7"
+dependencies = [
+ "Inflector",
+ "darling 0.14.4",
+ "mrml-common-macros",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "mrml-print-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3ed636b13c5df8ad22087f548be69cd1416c2f5929d687406e7c872528bd55"
+dependencies = [
+ "darling 0.14.4",
+ "mrml-common-macros",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "multer"
version = "2.0.4"
@@ -2047,6 +2241,12 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "quoted_printable"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a24039f627d8285853cc90dcddf8c1ebfaa91f834566948872b225b9a28ed1b6"
+
[[package]]
name = "rand"
version = "0.8.5"
@@ -2343,6 +2543,12 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
[[package]]
name = "rustix"
version = "0.36.11"
@@ -2369,6 +2575,18 @@ dependencies = [
"webpki",
]
+[[package]]
+name = "rustls"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07180898a28ed6a7f7ba2311594308f595e3dd2e3c3812fa0a80a47b45f17e5d"
+dependencies = [
+ "log",
+ "ring",
+ "rustls-webpki",
+ "sct",
+]
+
[[package]]
name = "rustls-pemfile"
version = "1.0.2"
@@ -2378,6 +2596,16 @@ dependencies = [
"base64 0.21.0",
]
+[[package]]
+name = "rustls-webpki"
+version = "0.100.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
[[package]]
name = "rustversion"
version = "1.0.12"
@@ -2526,7 +2754,7 @@ version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
dependencies = [
- "darling",
+ "darling 0.13.4",
"proc-macro2",
"quote",
"syn 1.0.109",
@@ -2712,7 +2940,7 @@ dependencies = [
"once_cell",
"paste",
"percent-encoding",
- "rustls",
+ "rustls 0.20.8",
"rustls-pemfile",
"serde",
"sha2",
@@ -2723,7 +2951,7 @@ dependencies = [
"thiserror",
"tokio-stream",
"url",
- "webpki-roots",
+ "webpki-roots 0.22.6",
]
[[package]]
@@ -2756,7 +2984,7 @@ checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024"
dependencies = [
"once_cell",
"tokio",
- "tokio-rustls",
+ "tokio-rustls 0.23.4",
]
[[package]]
@@ -2996,11 +3224,21 @@ version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
- "rustls",
+ "rustls 0.20.8",
"tokio",
"webpki",
]
+[[package]]
+name = "tokio-rustls"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5"
+dependencies = [
+ "rustls 0.21.0",
+ "tokio",
+]
+
[[package]]
name = "tokio-stream"
version = "0.1.12"
@@ -3419,6 +3657,15 @@ dependencies = [
"webpki",
]
+[[package]]
+name = "webpki-roots"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa54963694b65584e170cf5dc46aeb4dcaa5584e652ff5f3952e56d66aff0125"
+dependencies = [
+ "rustls-webpki",
+]
+
[[package]]
name = "winapi"
version = "0.3.9"
@@ -3549,6 +3796,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+[[package]]
+name = "xmlparser"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
+
[[package]]
name = "yansi"
version = "0.5.1"
diff --git a/Dockerfile b/Dockerfile
index edc804c..179291f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -22,6 +22,7 @@ FROM alpine:3.17.2
COPY --from=builder /ezidam/target/x86_64-unknown-linux-musl/release/ezidam /ezidam/ezidam
COPY crates/ezidam/static /ezidam/static
COPY crates/ezidam/templates /ezidam/templates
+COPY crates/email/templates /ezidam/email-templates
ENV ROCKET_CLI_COLORS=0
ENV ROCKET_ADDRESS=0.0.0.0
ENV ROCKET_PORT=8000
diff --git a/crates/email/Cargo.toml b/crates/email/Cargo.toml
new file mode 100644
index 0000000..56f3fc5
--- /dev/null
+++ b/crates/email/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "email"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+thiserror = { workspace = true }
+tera = "1.18.1"
+mrml = "2.0.0-rc2"
+serde = { workspace = true }
+
+[dependencies.lettre]
+version = "0.10.3"
+default-features = false
+features = [
+ # tokio, rustls
+ "tokio1",
+ "tokio1-rustls-tls",
+ # default features
+ "smtp-transport",
+ "pool",
+ "hostname",
+ "builder",
+]
\ No newline at end of file
diff --git a/crates/email/readme.md b/crates/email/readme.md
new file mode 100644
index 0000000..d0446bc
--- /dev/null
+++ b/crates/email/readme.md
@@ -0,0 +1,36 @@
+# email
+
+create and send emails from templates
+
+## template
+
+- `mjml` to create emails
+- `tera` to render emails with parameters
+
+## send
+
+- `lettre` to send the emails with smtp
+
+## rocket config
+
+- `from`: Sender of emails, usually name and email address
+- `transport`: Security method to send the mails. `unencrypted` or `tls` or `starttls`
+- `host`: Where to send smtp traffic
+- `port`: *optional*: Used when `transport` is `unencrypted`
+- `username` and `password`: *optional*: Used when `transport` is `tls` or `starttls`
+
+### `Rocket.toml`
+
+```toml
+[default.email]
+from = "ezidam You recently requested to reset the password of your ezidam account. Use the button below to reset it. This message will expire in {{ token_duration }} minutes. Can't click on the button? Use the link below: {{ user_email }} {{ now(utc=true) | date(format="%F %T %Z", timezone=user_timezone | default(value="UTC")) }} ezidam {{ ezidam_version }} Copyright ©
+ {{ now(utc=true) | date(format="%Y", timezone=user_timezone | default(value="UTC")) }}
+ philt3r technologies
+ Reset password
+