Microservice to bring 2FA to self hosted PDSes
92
fork

Configure Feed

Select the types of activity you want to include in your feed.

split up some code

authored by

Bailey Townsend and committed by tangled.org 04f863e2 500ac33c

+93 -53
+42 -10
Cargo.lock
··· 85 85 ] 86 86 87 87 [[package]] 88 + name = "async-channel" 89 + version = "1.9.0" 90 + source = "registry+https://github.com/rust-lang/crates.io-index" 91 + checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" 92 + dependencies = [ 93 + "concurrent-queue", 94 + "event-listener 2.5.3", 95 + "futures-core", 96 + ] 97 + 98 + [[package]] 99 + name = "async-channel" 100 + version = "2.5.0" 101 + source = "registry+https://github.com/rust-lang/crates.io-index" 102 + checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" 103 + dependencies = [ 104 + "concurrent-queue", 105 + "event-listener-strategy", 106 + "futures-core", 107 + "pin-project-lite", 108 + ] 109 + 110 + [[package]] 88 111 name = "async-compression" 89 112 version = "0.4.36" 90 113 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 139 162 "futures-lite", 140 163 "parking", 141 164 "polling", 142 - "rustix 1.1.2", 165 + "rustix", 143 166 "slab", 144 167 "windows-sys 0.61.2", 145 168 ] 146 169 147 170 [[package]] 148 171 name = "async-lock" 149 - version = "3.4.1" 172 + version = "3.4.2" 150 173 source = "registry+https://github.com/rust-lang/crates.io-index" 151 - checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" 174 + checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" 152 175 dependencies = [ 153 176 "event-listener 5.4.1", 154 177 "event-listener-strategy", ··· 170 193 "cfg-if", 171 194 "event-listener 5.4.1", 172 195 "futures-lite", 173 - "rustix 1.1.2", 196 + "rustix", 174 197 ] 175 198 176 199 [[package]] ··· 185 208 "cfg-if", 186 209 "futures-core", 187 210 "futures-io", 188 - "rustix 1.1.2", 211 + "rustix", 189 212 "signal-hook-registry", 190 213 "slab", 191 214 "windows-sys 0.61.2", ··· 2316 2339 ] 2317 2340 2318 2341 [[package]] 2342 + name = "linux-raw-sys" 2343 + version = "0.11.0" 2344 + source = "registry+https://github.com/rust-lang/crates.io-index" 2345 + checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 2346 + 2347 + [[package]] 2319 2348 name = "litemap" 2320 2349 version = "0.8.1" 2321 2350 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2335 2364 version = "0.4.29" 2336 2365 source = "registry+https://github.com/rust-lang/crates.io-index" 2337 2366 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 2367 + dependencies = [ 2368 + "value-bag", 2369 + ] 2338 2370 2339 2371 [[package]] 2340 2372 name = "loom" ··· 2920 2952 "concurrent-queue", 2921 2953 "hermit-abi", 2922 2954 "pin-project-lite", 2923 - "rustix 1.1.2", 2955 + "rustix", 2924 2956 "windows-sys 0.61.2", 2925 2957 ] 2926 2958 ··· 3417 3449 3418 3450 [[package]] 3419 3451 name = "rustix" 3420 - version = "1.1.2" 3452 + version = "1.1.3" 3421 3453 source = "registry+https://github.com/rust-lang/crates.io-index" 3422 - checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 3454 + checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" 3423 3455 dependencies = [ 3424 3456 "bitflags", 3425 3457 "errno", 3426 3458 "libc", 3427 - "linux-raw-sys 0.11.0", 3428 - "windows-sys 0.59.0", 3459 + "linux-raw-sys", 3460 + "windows-sys 0.52.0", 3429 3461 ] 3430 3462 3431 3463 [[package]]
+1 -1
Cargo.toml
··· 22 22 #Leaveing these two cause I think it is needed by the email crate for ssl 23 23 aws-lc-rs = "1.15.2" 24 24 rustls = { version = "0.23", default-features = false, features = ["tls12", "std", "logging", "aws_lc_rs"] } 25 - lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "tokio1", "tokio1-rustls"] } 25 + lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "sendmail-transport", "tokio1", "tokio1-rustls"] } 26 26 handlebars = { version = "6.4.0", features = ["rust-embed"] } 27 27 rust-embed = "8.9.0" 28 28 axum-template = { version = "3.0.0", features = ["handlebars"] }
+46
src/mailer.rs
··· 1 + use anyhow::Context; 2 + use lettre::{AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor}; 3 + use std::env; 4 + use url::Url; 5 + 6 + pub enum Mailer { 7 + Smtp(AsyncSmtpTransport<Tokio1Executor>), 8 + Sendmail(AsyncSendmailTransport<Tokio1Executor>), 9 + } 10 + 11 + impl Mailer { 12 + pub async fn send(&self, msg: Message) -> anyhow::Result<()> { 13 + match self { 14 + Mailer::Smtp(m) => { 15 + m.send(msg).await.context("SMTP send failed")?; 16 + Ok(()) 17 + } 18 + Mailer::Sendmail(m) => { 19 + m.send(msg).await.context("sendmail send failed")?; 20 + Ok(()) 21 + } 22 + } 23 + } 24 + } 25 + 26 + pub fn build_mailer_from_env() -> anyhow::Result<Mailer> { 27 + let raw = env::var("PDS_EMAIL_SMTP_URL") 28 + .context("PDS_EMAIL_SMTP_URL is not set in your pds.env file")?; 29 + 30 + let url = Url::parse(&raw).context("PDS_EMAIL_SMTP_URL is not a valid URL")?; 31 + 32 + let use_sendmail = url.scheme() == "sendmail" 33 + || url 34 + .query_pairs() 35 + .any(|(k, v)| k == "sendmail" && v == "true"); 36 + 37 + if use_sendmail { 38 + Ok(Mailer::Sendmail( 39 + AsyncSendmailTransport::<Tokio1Executor>::new(), 40 + )) 41 + } else { 42 + Ok(Mailer::Smtp( 43 + AsyncSmtpTransport::<Tokio1Executor>::from_url(raw.as_str())?.build(), 44 + )) 45 + } 46 + }
+4 -42
src/main.rs
··· 1 1 #![warn(clippy::unwrap_used)] 2 2 use crate::gate::{get_gate, post_gate}; 3 + use crate::mailer::{Mailer, build_mailer_from_env}; 3 4 use crate::oauth_provider::sign_in; 4 5 use crate::xrpc::com_atproto_server::{ 5 6 create_account, create_session, describe_server, get_session, update_email, 6 7 }; 7 - use anyhow::{Result, Context}; 8 + use anyhow::Result; 8 9 use axum::{ 9 10 Router, 10 11 body::Body, ··· 19 20 use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; 20 21 use jacquard_common::types::did::Did; 21 22 use jacquard_identity::{PublicResolver, resolver::PlcSource}; 22 - use lettre::{AsyncTransport, AsyncSmtpTransport, AsyncSendmailTransport, Message, Tokio1Executor}; 23 23 use rand::Rng; 24 24 use rust_embed::RustEmbed; 25 25 use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode}; ··· 37 37 }; 38 38 use tracing::log; 39 39 use tracing_subscriber::{EnvFilter, fmt, prelude::*}; 40 - use url::Url; 41 40 42 41 mod auth; 43 42 mod gate; 44 43 pub mod helpers; 44 + pub mod mailer; 45 45 mod middleware; 46 46 mod oauth_provider; 47 47 mod xrpc; ··· 160 160 app_config: AppConfig, 161 161 } 162 162 163 - pub enum Mailer { 164 - Smtp(AsyncSmtpTransport<Tokio1Executor>), 165 - Sendmail(AsyncSendmailTransport<Tokio1Executor>), 166 - } 167 - 168 - impl Mailer { 169 - pub async fn send(&self, msg: Message) -> Result<()> { 170 - match self { 171 - Mailer::Smtp(m) => { 172 - m.send(msg).await.context("SMTP send failed")?; 173 - Ok(()) 174 - } 175 - Mailer::Sendmail(m) => { 176 - m.send(msg).await.context("sendmail send failed")?; 177 - Ok(()) 178 - } 179 - } 180 - } 181 - } 182 - 183 - fn build_mailer_from_env() -> Result<Mailer> { 184 - let raw = env::var("PDS_EMAIL_SMTP_URL") 185 - .context("PDS_EMAIL_SMTP_URL is not set in your pds.env file")?; 186 - 187 - let url = Url::parse(&raw).context("PDS_EMAIL_SMTP_URL is not a valid URL")?; 188 - 189 - let use_sendmail = url.scheme() == "sendmail" 190 - || url.query_pairs().any(|(k, v)| k == "sendmail" && v == "true"); 191 - 192 - if use_sendmail { 193 - Ok(Mailer::Sendmail(AsyncSendmailTransport::<Tokio1Executor>::new())) 194 - } else { 195 - Ok(Mailer::Smtp( 196 - AsyncSmtpTransport::<Tokio1Executor>::from_url(raw.as_str())? 197 - .build(), 198 - )) 199 - } 200 - } 201 - 202 163 async fn root_handler() -> impl axum::response::IntoResponse { 203 164 let body = r" 204 165 ··· 254 215 let account_db_url = format!("{pds_root}/account.sqlite"); 255 216 256 217 let account_options = SqliteConnectOptions::new() 218 + .journal_mode(SqliteJournalMode::Wal) 257 219 .filename(account_db_url) 258 220 .busy_timeout(Duration::from_secs(5)); 259 221