email sending & magic links
/ build (push) Successful in 49s Details
/ build_x64 (push) Successful in 2m6s Details
/ build_arm64 (push) Successful in 2m34s Details
/ build_win64 (push) Successful in 2m33s Details

This commit is contained in:
core 2023-11-19 11:31:30 -05:00
parent 79b1765ed5
commit 5204994769
Signed by: core
GPG Key ID: FDBF740DADDCEECF
11 changed files with 530 additions and 17 deletions

416
Cargo.lock generated
View File

@ -70,7 +70,7 @@ dependencies = [
"tokio", "tokio",
"tokio-util", "tokio-util",
"tracing", "tracing",
"zstd", "zstd 0.12.4",
] ]
[[package]] [[package]]
@ -211,6 +211,17 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aes"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.6" version = "0.8.6"
@ -349,6 +360,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.5" version = "0.21.5"
@ -476,6 +493,27 @@ dependencies = [
"bytes", "bytes",
] ]
[[package]]
name = "bzip2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.83" version = "1.0.83"
@ -522,6 +560,16 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]] [[package]]
name = "clang-sys" name = "clang-sys"
version = "1.6.1" version = "1.6.1"
@ -596,6 +644,12 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.4.0" version = "0.4.0"
@ -647,6 +701,15 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crossterm" name = "crossterm"
version = "0.25.0" version = "0.25.0"
@ -756,6 +819,12 @@ dependencies = [
"syn 2.0.38", "syn 2.0.38",
] ]
[[package]]
name = "data-encoding"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.8" version = "0.7.8"
@ -937,6 +1006,18 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "enum-as-inner"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.10.1" version = "0.10.1"
@ -1082,6 +1163,16 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "gethostname"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
dependencies = [
"libc",
"windows-targets",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.10" version = "0.2.10"
@ -1154,6 +1245,57 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hickory-proto"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091a6fbccf4860009355e3efc52ff4acf37a63489aad7435372d44ceeb6fbbcf"
dependencies = [
"async-trait",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"idna",
"ipnet",
"once_cell",
"rand",
"ring 0.16.20",
"rustls",
"rustls-pemfile",
"thiserror",
"tinyvec",
"tokio",
"tokio-rustls",
"tracing",
"url",
]
[[package]]
name = "hickory-resolver"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35b8f021164e6a984c9030023544c57789c51760065cd510572fedcfb04164e8"
dependencies = [
"cfg-if",
"futures-util",
"hickory-proto",
"ipconfig",
"lru-cache",
"once_cell",
"parking_lot",
"rand",
"resolv-conf",
"rustls",
"smallvec",
"thiserror",
"tokio",
"tokio-rustls",
"tracing",
]
[[package]] [[package]]
name = "hmac" name = "hmac"
version = "0.12.1" version = "0.12.1"
@ -1172,6 +1314,17 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[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]] [[package]]
name = "http" name = "http"
version = "0.2.9" version = "0.2.9"
@ -1311,6 +1464,27 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]]
name = "ipconfig"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
"socket2 0.5.5",
"widestring",
"windows-sys 0.48.0",
"winreg",
]
[[package]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.9.0" version = "2.9.0"
@ -1389,6 +1563,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.10" version = "0.4.10"
@ -1428,6 +1608,79 @@ version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "mail-auth"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab6524549b92c6f1250ddefe10f67bcedb9de0674a026b21e88dc1958437f8a6"
dependencies = [
"ahash",
"flate2",
"hickory-resolver",
"lru-cache",
"mail-builder",
"mail-parser",
"parking_lot",
"quick-xml",
"ring 0.17.5",
"rustls-pemfile",
"serde",
"serde_json",
"zip",
]
[[package]]
name = "mail-builder"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef70f53409852d2612f2249810cbbe0c9931ca25b739b734bafc7f61d88051d4"
dependencies = [
"gethostname",
]
[[package]]
name = "mail-parser"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e51d275d90a41584d12ea25fc4a7d7d00236a4718308b994ed13a7ff90a6985"
dependencies = [
"encoding_rs",
]
[[package]]
name = "mail-send"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cbc58a799366b3b2956a2c5ae7e2892ea34b3016343cbbdc5deb844aa6c0973"
dependencies = [
"base64 0.20.0",
"gethostname",
"mail-auth",
"mail-builder",
"md5",
"rand",
"rustls",
"smtp-proto",
"tokio",
"tokio-rustls",
"webpki-roots",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]] [[package]]
name = "md-5" name = "md-5"
version = "0.10.6" version = "0.10.6"
@ -1438,6 +1691,12 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.6.4" version = "2.6.4"
@ -1599,12 +1858,35 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "password-hash"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.14" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pbkdf2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
dependencies = [
"digest",
"hmac",
"password-hash",
"sha2",
]
[[package]] [[package]]
name = "peeking_take_while" name = "peeking_take_while"
version = "0.1.2" version = "0.1.2"
@ -1757,6 +2039,12 @@ dependencies = [
"checked_int_cast", "checked_int_cast",
] ]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quick-protobuf" name = "quick-protobuf"
version = "0.8.1" version = "0.8.1"
@ -1766,6 +2054,15 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "quick-xml"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.33" version = "1.0.33"
@ -1903,6 +2200,31 @@ dependencies = [
"winreg", "winreg",
] ]
[[package]]
name = "resolv-conf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
dependencies = [
"hostname",
"quick-error",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin 0.5.2",
"untrusted 0.7.1",
"web-sys",
"winapi",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.5" version = "0.17.5"
@ -1912,8 +2234,8 @@ dependencies = [
"cc", "cc",
"getrandom", "getrandom",
"libc", "libc",
"spin", "spin 0.9.8",
"untrusted", "untrusted 0.9.0",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -1958,7 +2280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c"
dependencies = [ dependencies = [
"log", "log",
"ring", "ring 0.17.5",
"rustls-webpki", "rustls-webpki",
"sct", "sct",
] ]
@ -1978,8 +2300,8 @@ version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [ dependencies = [
"ring", "ring 0.17.5",
"untrusted", "untrusted 0.9.0",
] ]
[[package]] [[package]]
@ -2010,8 +2332,8 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [ dependencies = [
"ring", "ring 0.17.5",
"untrusted", "untrusted 0.9.0",
] ]
[[package]] [[package]]
@ -2211,6 +2533,12 @@ version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "smtp-proto"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b756ac662e92a0e5b360349bea5f0b0784d4be4541eff2972049dfdfd7f862"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.10" version = "0.4.10"
@ -2231,6 +2559,12 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.8" version = "0.9.8"
@ -2582,9 +2916,21 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [ dependencies = [
"log", "log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes",
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.32" version = "0.1.32"
@ -2606,6 +2952,7 @@ dependencies = [
"diesel_migrations", "diesel_migrations",
"env_logger", "env_logger",
"log", "log",
"mail-send",
"rand", "rand",
"serde", "serde",
"serde_json", "serde_json",
@ -2667,6 +3014,12 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.9.0" version = "0.9.0"
@ -2815,6 +3168,12 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "widestring"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -3049,13 +3408,52 @@ dependencies = [
"syn 2.0.38", "syn 2.0.38",
] ]
[[package]]
name = "zip"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
dependencies = [
"aes",
"byteorder",
"bzip2",
"constant_time_eq",
"crc32fast",
"crossbeam-utils",
"flate2",
"hmac",
"pbkdf2",
"sha1",
"time",
"zstd 0.11.2+zstd.1.5.2",
]
[[package]]
name = "zstd"
version = "0.11.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
dependencies = [
"zstd-safe 5.0.2+zstd.1.5.2",
]
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.12.4" version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
dependencies = [ dependencies = [
"zstd-safe", "zstd-safe 6.0.6",
]
[[package]]
name = "zstd-safe"
version = "5.0.2+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
dependencies = [
"libc",
"zstd-sys",
] ]
[[package]] [[package]]

View File

@ -23,4 +23,5 @@ diesel = { version = "2" }
diesel-async = { version = "0.4", features = ["postgres", "bb8", "async-connection-wrapper"] } diesel-async = { version = "0.4", features = ["postgres", "bb8", "async-connection-wrapper"] }
diesel_migrations = "2" diesel_migrations = "2"
bb8 = "0.8" bb8 = "0.8"
rand = "0.8" rand = "0.8"
mail-send = "0.4"

View File

@ -15,4 +15,28 @@ bind = { ip = "127.0.0.1", port = 8080 }
# [database] contains options for the Postgres database used for all data storage # [database] contains options for the Postgres database used for all data storage
[database] [database]
# (Required) The postgres database connection url to use # (Required) The postgres database connection url to use
url = "postgres://postgres:postgres@localhost/trifid2" url = "postgres://postgres:postgres@localhost/trifid2"
# [email] contains options for the SMTP connection used to send magic link emails
[email]
# (Required) The mail server to connect to
server = "mail.e3t.cc"
# (Required) The SMTP port to connect to.
port = 587
# (Required) The username to authenticate with.
username = "username"
# (Required) The password to authenticate with. If set to %PASSWORD%, will be filled from the environment variable TRIFID_EMAIL_PASSWORD.
password = "$PASSWORD$"
# (Required) The "From Name" to send the email from
from_name = "Trifid"
# (Required) The address to send the email from
from_email = "trifid@e3t.cc"
# (Required) The email template to use. %TOKEN% will be replaced with the magic link token.
template = "Click this link to sign in! http://localhost:5173/magic-link?magicLinkToken=%TOKEN%"
# (Required) Should STARTTLS be used?
starttls = false
# [tokens] contains options for token expiry
[tokens]
# (Required) How long should magic links be valid for, in seconds?
magic_link_expiry_seconds = 3600 # 1 hour

View File

@ -0,0 +1 @@
DROP TABLE magic_links;

View File

@ -0,0 +1,5 @@
CREATE TABLE magic_links (
id VARCHAR NOT NULL PRIMARY KEY,
user_id VARCHAR NOT NULL REFERENCES users(id),
expires TIMESTAMP NOT NULL
);

View File

@ -4,7 +4,9 @@ use serde::Deserialize;
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
pub struct Config { pub struct Config {
pub server: ConfigServer, pub server: ConfigServer,
pub database: ConfigDatabase pub database: ConfigDatabase,
pub email: ConfigEmail,
pub tokens: ConfigTokens
} }
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
@ -22,4 +24,21 @@ pub struct ConfigServerBind {
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
pub struct ConfigDatabase { pub struct ConfigDatabase {
pub url: String pub url: String
}
#[derive(Deserialize, Clone)]
pub struct ConfigEmail {
pub server: String,
pub port: u16,
pub username: String,
pub password: String,
pub from_name: String,
pub from_email: String,
pub template: String,
pub starttls: bool
}
#[derive(Deserialize, Clone)]
pub struct ConfigTokens {
pub magic_link_expiry_seconds: u64
} }

25
trifid-api/src/email.rs Normal file
View File

@ -0,0 +1,25 @@
use std::error::Error;
use mail_send::mail_builder::MessageBuilder;
use mail_send::SmtpClientBuilder;
use crate::config::Config;
pub async fn send_email(token: &str, to_address: &str, config: &Config) -> Result<(), Box<dyn Error>> {
let message = MessageBuilder::new()
.from((config.email.from_name.as_str(), config.email.from_email.as_str()))
.to(vec![to_address])
.subject("Trifid - Log In")
.text_body(config.email.template.replace("%TOKEN%", token));
let mut password = config.email.password.clone();
if password == "%PASSWORD%" {
password = std::env::var("TRIFID_EMAIL_PASSWORD")?.clone();
}
SmtpClientBuilder::new(config.email.server.as_str(), config.email.port)
.implicit_tls(!config.email.starttls)
.credentials((config.email.username.as_str(), password.as_str()))
.connect().await?
.send(message).await?;
Ok(())
}

View File

@ -22,6 +22,7 @@ pub mod schema;
pub mod models; pub mod models;
#[macro_use] #[macro_use]
pub mod id; pub mod id;
pub mod email;
#[derive(Clone)] #[derive(Clone)]

View File

@ -1,9 +1,20 @@
use diesel::{Insertable, Queryable, Selectable}; use std::time::SystemTime;
use diesel::{Associations, Identifiable, Insertable, Queryable, Selectable};
#[derive(Queryable, Selectable, Insertable)] #[derive(Queryable, Selectable, Insertable, Identifiable, Debug, PartialEq)]
#[diesel(table_name = crate::schema::users)] #[diesel(table_name = crate::schema::users)]
#[diesel(check_for_backend(diesel::pg::Pg))] #[diesel(check_for_backend(diesel::pg::Pg))]
pub struct User { pub struct User {
pub id: String, pub id: String,
pub email: String pub email: String
}
#[derive(Queryable, Selectable, Insertable, Identifiable, Associations, Debug, PartialEq)]
#[diesel(belongs_to(User))]
#[diesel(table_name = crate::schema::magic_links)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct MagicLink {
pub id: String,
pub user_id: String,
pub expires: SystemTime
} }

View File

@ -1,11 +1,13 @@
use std::time::{Duration, SystemTime};
use actix_web::post; use actix_web::post;
use actix_web::web::{Data, Json}; use actix_web::web::{Data, Json};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{AppState, randid}; use crate::{AppState, randid};
use crate::models::User; use crate::models::{MagicLink, User};
use crate::response::JsonAPIResponse; use crate::response::JsonAPIResponse;
use crate::schema::users; use crate::schema::{users, magic_links};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use crate::email::send_email;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct SignupRequest { pub struct SignupRequest {
@ -24,12 +26,23 @@ pub struct SignupResponseMetadata {}
pub async fn signup_req(req: Json<SignupRequest>, state: Data<AppState>) -> JsonAPIResponse<SignupResponse> { pub async fn signup_req(req: Json<SignupRequest>, state: Data<AppState>) -> JsonAPIResponse<SignupResponse> {
let mut conn = handle_error!(state.pool.get().await); let mut conn = handle_error!(state.pool.get().await);
let user_id = randid!(id "user");
let new_user = User { let new_user = User {
id: randid!(id "user"), id: user_id.clone(),
email: req.email.clone(), email: req.email.clone(),
}; };
handle_error!(diesel::insert_into(users::table).values(&new_user).execute(&mut conn).await); handle_error!(diesel::insert_into(users::table).values(&new_user).execute(&mut conn).await);
let new_magic_link = MagicLink {
id: randid!(token "ml"),
user_id,
expires: SystemTime::now() + Duration::from_secs(state.config.tokens.magic_link_expiry_seconds)
};
handle_error!(diesel::insert_into(magic_links::table).values(&new_magic_link).execute(&mut conn).await);
handle_error!(send_email(&new_magic_link.id, &req.email, &state.config).await);
ok!(SignupResponse { data: None, metadata: SignupResponseMetadata {} }) ok!(SignupResponse { data: None, metadata: SignupResponseMetadata {} })
} }

View File

@ -1,8 +1,23 @@
// @generated automatically by Diesel CLI. // @generated automatically by Diesel CLI.
diesel::table! {
magic_links (id) {
id -> Varchar,
user_id -> Varchar,
expires -> Timestamp,
}
}
diesel::table! { diesel::table! {
users (id) { users (id) {
id -> Varchar, id -> Varchar,
email -> Varchar, email -> Varchar,
} }
} }
diesel::joinable!(magic_links -> users (user_id));
diesel::allow_tables_to_appear_in_same_query!(
magic_links,
users,
);