tangled
alpha
login
or
join now
baileytownsend.dev
/
pds-gatekeeper
89
fork
atom
Microservice to bring 2FA to self hosted PDSes
89
fork
atom
overview
issues
1
pulls
3
pipelines
split up some code
baileytownsend.dev
3 weeks ago
a0fc6815
bffa984c
+93
-53
4 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
src
mailer.rs
main.rs
+42
-10
Cargo.lock
reviewed
···
85
85
]
86
86
87
87
[[package]]
88
88
+
name = "async-channel"
89
89
+
version = "1.9.0"
90
90
+
source = "registry+https://github.com/rust-lang/crates.io-index"
91
91
+
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
92
92
+
dependencies = [
93
93
+
"concurrent-queue",
94
94
+
"event-listener 2.5.3",
95
95
+
"futures-core",
96
96
+
]
97
97
+
98
98
+
[[package]]
99
99
+
name = "async-channel"
100
100
+
version = "2.5.0"
101
101
+
source = "registry+https://github.com/rust-lang/crates.io-index"
102
102
+
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
103
103
+
dependencies = [
104
104
+
"concurrent-queue",
105
105
+
"event-listener-strategy",
106
106
+
"futures-core",
107
107
+
"pin-project-lite",
108
108
+
]
109
109
+
110
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
142
-
"rustix 1.1.2",
165
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
149
-
version = "3.4.1"
172
172
+
version = "3.4.2"
150
173
source = "registry+https://github.com/rust-lang/crates.io-index"
151
151
-
checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
174
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
173
-
"rustix 1.1.2",
196
196
+
"rustix",
174
197
]
175
198
176
199
[[package]]
···
185
208
"cfg-if",
186
209
"futures-core",
187
210
"futures-io",
188
188
-
"rustix 1.1.2",
211
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
2342
+
name = "linux-raw-sys"
2343
2343
+
version = "0.11.0"
2344
2344
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2345
2345
+
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
2346
2346
+
2347
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
2367
+
dependencies = [
2368
2368
+
"value-bag",
2369
2369
+
]
2338
2370
2339
2371
[[package]]
2340
2372
name = "loom"
···
2920
2952
"concurrent-queue",
2921
2953
"hermit-abi",
2922
2954
"pin-project-lite",
2923
2923
-
"rustix 1.1.2",
2955
2955
+
"rustix",
2924
2956
"windows-sys 0.61.2",
2925
2957
]
2926
2958
···
3417
3449
3418
3450
[[package]]
3419
3451
name = "rustix"
3420
3420
-
version = "1.1.2"
3452
3452
+
version = "1.1.3"
3421
3453
source = "registry+https://github.com/rust-lang/crates.io-index"
3422
3422
-
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
3454
3454
+
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
3423
3455
dependencies = [
3424
3456
"bitflags",
3425
3457
"errno",
3426
3458
"libc",
3427
3427
-
"linux-raw-sys 0.11.0",
3428
3428
-
"windows-sys 0.59.0",
3459
3459
+
"linux-raw-sys",
3460
3460
+
"windows-sys 0.52.0",
3429
3461
]
3430
3462
3431
3463
[[package]]
+1
-1
Cargo.toml
reviewed
···
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
25
-
lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "tokio1", "tokio1-rustls"] }
25
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
reviewed
···
1
1
+
use anyhow::Context;
2
2
+
use lettre::{AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor};
3
3
+
use std::env;
4
4
+
use url::Url;
5
5
+
6
6
+
pub enum Mailer {
7
7
+
Smtp(AsyncSmtpTransport<Tokio1Executor>),
8
8
+
Sendmail(AsyncSendmailTransport<Tokio1Executor>),
9
9
+
}
10
10
+
11
11
+
impl Mailer {
12
12
+
pub async fn send(&self, msg: Message) -> anyhow::Result<()> {
13
13
+
match self {
14
14
+
Mailer::Smtp(m) => {
15
15
+
m.send(msg).await.context("SMTP send failed")?;
16
16
+
Ok(())
17
17
+
}
18
18
+
Mailer::Sendmail(m) => {
19
19
+
m.send(msg).await.context("sendmail send failed")?;
20
20
+
Ok(())
21
21
+
}
22
22
+
}
23
23
+
}
24
24
+
}
25
25
+
26
26
+
pub fn build_mailer_from_env() -> anyhow::Result<Mailer> {
27
27
+
let raw = env::var("PDS_EMAIL_SMTP_URL")
28
28
+
.context("PDS_EMAIL_SMTP_URL is not set in your pds.env file")?;
29
29
+
30
30
+
let url = Url::parse(&raw).context("PDS_EMAIL_SMTP_URL is not a valid URL")?;
31
31
+
32
32
+
let use_sendmail = url.scheme() == "sendmail"
33
33
+
|| url
34
34
+
.query_pairs()
35
35
+
.any(|(k, v)| k == "sendmail" && v == "true");
36
36
+
37
37
+
if use_sendmail {
38
38
+
Ok(Mailer::Sendmail(
39
39
+
AsyncSendmailTransport::<Tokio1Executor>::new(),
40
40
+
))
41
41
+
} else {
42
42
+
Ok(Mailer::Smtp(
43
43
+
AsyncSmtpTransport::<Tokio1Executor>::from_url(raw.as_str())?.build(),
44
44
+
))
45
45
+
}
46
46
+
}
+4
-42
src/main.rs
reviewed
···
1
1
#![warn(clippy::unwrap_used)]
2
2
use crate::gate::{get_gate, post_gate};
3
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
7
-
use anyhow::{Result, Context};
8
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
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
40
-
use url::Url;
41
40
42
41
mod auth;
43
42
mod gate;
44
43
pub mod helpers;
44
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
163
-
pub enum Mailer {
164
164
-
Smtp(AsyncSmtpTransport<Tokio1Executor>),
165
165
-
Sendmail(AsyncSendmailTransport<Tokio1Executor>),
166
166
-
}
167
167
-
168
168
-
impl Mailer {
169
169
-
pub async fn send(&self, msg: Message) -> Result<()> {
170
170
-
match self {
171
171
-
Mailer::Smtp(m) => {
172
172
-
m.send(msg).await.context("SMTP send failed")?;
173
173
-
Ok(())
174
174
-
}
175
175
-
Mailer::Sendmail(m) => {
176
176
-
m.send(msg).await.context("sendmail send failed")?;
177
177
-
Ok(())
178
178
-
}
179
179
-
}
180
180
-
}
181
181
-
}
182
182
-
183
183
-
fn build_mailer_from_env() -> Result<Mailer> {
184
184
-
let raw = env::var("PDS_EMAIL_SMTP_URL")
185
185
-
.context("PDS_EMAIL_SMTP_URL is not set in your pds.env file")?;
186
186
-
187
187
-
let url = Url::parse(&raw).context("PDS_EMAIL_SMTP_URL is not a valid URL")?;
188
188
-
189
189
-
let use_sendmail = url.scheme() == "sendmail"
190
190
-
|| url.query_pairs().any(|(k, v)| k == "sendmail" && v == "true");
191
191
-
192
192
-
if use_sendmail {
193
193
-
Ok(Mailer::Sendmail(AsyncSendmailTransport::<Tokio1Executor>::new()))
194
194
-
} else {
195
195
-
Ok(Mailer::Smtp(
196
196
-
AsyncSmtpTransport::<Tokio1Executor>::from_url(raw.as_str())?
197
197
-
.build(),
198
198
-
))
199
199
-
}
200
200
-
}
201
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
218
+
.journal_mode(SqliteJournalMode::Wal)
257
219
.filename(account_db_url)
258
220
.busy_timeout(Duration::from_secs(5));
259
221