Originally from @eriko.eurosky.social with some changes
+262
-1
Cargo.lock
+262
-1
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"
···
98
121
]
99
122
100
123
[[package]]
124
+
name = "async-executor"
125
+
version = "1.13.3"
126
+
source = "registry+https://github.com/rust-lang/crates.io-index"
127
+
checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
128
+
dependencies = [
129
+
"async-task",
130
+
"concurrent-queue",
131
+
"fastrand",
132
+
"futures-lite",
133
+
"pin-project-lite",
134
+
"slab",
135
+
]
136
+
137
+
[[package]]
138
+
name = "async-global-executor"
139
+
version = "2.4.1"
140
+
source = "registry+https://github.com/rust-lang/crates.io-index"
141
+
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
142
+
dependencies = [
143
+
"async-channel 2.5.0",
144
+
"async-executor",
145
+
"async-io",
146
+
"async-lock",
147
+
"blocking",
148
+
"futures-lite",
149
+
"once_cell",
150
+
]
151
+
152
+
[[package]]
153
+
name = "async-io"
154
+
version = "2.6.0"
155
+
source = "registry+https://github.com/rust-lang/crates.io-index"
156
+
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
157
+
dependencies = [
158
+
"autocfg",
159
+
"cfg-if",
160
+
"concurrent-queue",
161
+
"futures-io",
162
+
"futures-lite",
163
+
"parking",
164
+
"polling",
165
+
"rustix",
166
+
"slab",
167
+
"windows-sys 0.61.2",
168
+
]
169
+
170
+
[[package]]
171
+
name = "async-lock"
172
+
version = "3.4.2"
173
+
source = "registry+https://github.com/rust-lang/crates.io-index"
174
+
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
175
+
dependencies = [
176
+
"event-listener 5.4.1",
177
+
"event-listener-strategy",
178
+
"pin-project-lite",
179
+
]
180
+
181
+
[[package]]
182
+
name = "async-process"
183
+
version = "2.5.0"
184
+
source = "registry+https://github.com/rust-lang/crates.io-index"
185
+
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
186
+
dependencies = [
187
+
"async-channel 2.5.0",
188
+
"async-io",
189
+
"async-lock",
190
+
"async-signal",
191
+
"async-task",
192
+
"blocking",
193
+
"cfg-if",
194
+
"event-listener 5.4.1",
195
+
"futures-lite",
196
+
"rustix",
197
+
]
198
+
199
+
[[package]]
200
+
name = "async-signal"
201
+
version = "0.2.13"
202
+
source = "registry+https://github.com/rust-lang/crates.io-index"
203
+
checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c"
204
+
dependencies = [
205
+
"async-io",
206
+
"async-lock",
207
+
"atomic-waker",
208
+
"cfg-if",
209
+
"futures-core",
210
+
"futures-io",
211
+
"rustix",
212
+
"signal-hook-registry",
213
+
"slab",
214
+
"windows-sys 0.61.2",
215
+
]
216
+
217
+
[[package]]
218
+
name = "async-std"
219
+
version = "1.13.2"
220
+
source = "registry+https://github.com/rust-lang/crates.io-index"
221
+
checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
222
+
dependencies = [
223
+
"async-channel 1.9.0",
224
+
"async-global-executor",
225
+
"async-io",
226
+
"async-lock",
227
+
"async-process",
228
+
"crossbeam-utils",
229
+
"futures-channel",
230
+
"futures-core",
231
+
"futures-io",
232
+
"futures-lite",
233
+
"gloo-timers",
234
+
"kv-log-macro",
235
+
"log",
236
+
"memchr",
237
+
"once_cell",
238
+
"pin-project-lite",
239
+
"pin-utils",
240
+
"slab",
241
+
"wasm-bindgen-futures",
242
+
]
243
+
244
+
[[package]]
245
+
name = "async-task"
246
+
version = "4.7.1"
247
+
source = "registry+https://github.com/rust-lang/crates.io-index"
248
+
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
249
+
250
+
[[package]]
101
251
name = "async-trait"
102
252
version = "0.1.89"
103
253
source = "registry+https://github.com/rust-lang/crates.io-index"
···
290
440
]
291
441
292
442
[[package]]
443
+
name = "blocking"
444
+
version = "1.6.2"
445
+
source = "registry+https://github.com/rust-lang/crates.io-index"
446
+
checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
447
+
dependencies = [
448
+
"async-channel 2.5.0",
449
+
"async-task",
450
+
"futures-io",
451
+
"futures-lite",
452
+
"piper",
453
+
]
454
+
455
+
[[package]]
293
456
294
457
295
458
···
1009
1172
1010
1173
[[package]]
1011
1174
name = "event-listener"
1175
+
version = "2.5.3"
1176
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1177
+
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
1178
+
1179
+
[[package]]
1180
+
name = "event-listener"
1012
1181
version = "5.4.1"
1013
1182
source = "registry+https://github.com/rust-lang/crates.io-index"
1014
1183
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
···
1019
1188
]
1020
1189
1021
1190
[[package]]
1191
+
name = "event-listener-strategy"
1192
+
version = "0.5.4"
1193
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1194
+
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
1195
+
dependencies = [
1196
+
"event-listener 5.4.1",
1197
+
"pin-project-lite",
1198
+
]
1199
+
1200
+
[[package]]
1022
1201
name = "fastrand"
1023
1202
version = "2.3.0"
1024
1203
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1302
1481
]
1303
1482
1304
1483
[[package]]
1484
+
name = "gloo-timers"
1485
+
version = "0.3.0"
1486
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1487
+
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
1488
+
dependencies = [
1489
+
"futures-channel",
1490
+
"futures-core",
1491
+
"js-sys",
1492
+
"wasm-bindgen",
1493
+
]
1494
+
1495
+
[[package]]
1305
1496
name = "governor"
1306
1497
version = "0.10.4"
1307
1498
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1465
1656
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
1466
1657
1467
1658
[[package]]
1659
+
name = "hermit-abi"
1660
+
version = "0.5.2"
1661
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1662
+
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
1663
+
1664
+
[[package]]
1468
1665
name = "hex"
1469
1666
1470
1667
···
2050
2247
]
2051
2248
2052
2249
[[package]]
2250
+
name = "kv-log-macro"
2251
+
version = "1.0.7"
2252
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2253
+
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
2254
+
dependencies = [
2255
+
"log",
2256
+
]
2257
+
2258
+
[[package]]
2053
2259
name = "langtag"
2054
2260
version = "0.4.0"
2055
2261
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2075
2281
source = "registry+https://github.com/rust-lang/crates.io-index"
2076
2282
checksum = "9e13e10e8818f8b2a60f52cb127041d388b89f3a96a62be9ceaffa22262fef7f"
2077
2283
dependencies = [
2284
+
"async-std",
2078
2285
"async-trait",
2079
2286
"base64",
2080
2287
"chumsky",
···
2132
2339
]
2133
2340
2134
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]]
2135
2348
name = "litemap"
2136
2349
version = "0.8.1"
2137
2350
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2151
2364
version = "0.4.29"
2152
2365
source = "registry+https://github.com/rust-lang/crates.io-index"
2153
2366
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2367
+
dependencies = [
2368
+
"value-bag",
2369
+
]
2154
2370
2155
2371
[[package]]
2156
2372
name = "loom"
···
2594
2810
"tower_governor",
2595
2811
"tracing",
2596
2812
"tracing-subscriber",
2813
+
"url",
2597
2814
"urlencoding",
2598
2815
"valuable",
2599
2816
]
···
2689
2906
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
2690
2907
2691
2908
[[package]]
2909
+
name = "piper"
2910
+
version = "0.2.4"
2911
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2912
+
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
2913
+
dependencies = [
2914
+
"atomic-waker",
2915
+
"fastrand",
2916
+
"futures-io",
2917
+
]
2918
+
2919
+
[[package]]
2692
2920
name = "pkcs1"
2693
2921
version = "0.7.5"
2694
2922
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2716
2944
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
2717
2945
2718
2946
[[package]]
2947
+
name = "polling"
2948
+
version = "3.11.0"
2949
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2950
+
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
2951
+
dependencies = [
2952
+
"cfg-if",
2953
+
"concurrent-queue",
2954
+
"hermit-abi",
2955
+
"pin-project-lite",
2956
+
"rustix",
2957
+
"windows-sys 0.61.2",
2958
+
]
2959
+
2960
+
[[package]]
2719
2961
name = "portable-atomic"
2720
2962
2721
2963
···
3207
3449
]
3208
3450
3209
3451
[[package]]
3452
+
name = "rustix"
3453
+
version = "1.1.3"
3454
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3455
+
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
3456
+
dependencies = [
3457
+
"bitflags",
3458
+
"errno",
3459
+
"libc",
3460
+
"linux-raw-sys",
3461
+
"windows-sys 0.52.0",
3462
+
]
3463
+
3464
+
[[package]]
3210
3465
name = "rustls"
3211
3466
version = "0.23.35"
3212
3467
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3667
3922
"crc",
3668
3923
"crossbeam-queue",
3669
3924
"either",
3670
-
"event-listener",
3925
+
"event-listener 5.4.1",
3671
3926
"futures-core",
3672
3927
"futures-intrusive",
3673
3928
"futures-io",
···
4439
4694
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
4440
4695
4441
4696
[[package]]
4697
+
name = "value-bag"
4698
+
version = "1.12.0"
4699
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4700
+
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
4701
+
4702
+
[[package]]
4442
4703
name = "vcpkg"
+2
-1
Cargo.toml
+2
-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"] }
···
35
35
multibase = "0.9.2"
36
36
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
37
37
urlencoding = "2.1"
38
+
url = "2.5.7"
38
39
html-escape = "0.2.13"
39
40
josekit = "0.10.3"
40
41
dashmap = "6.1"
+5
-5
src/gate.rs
+5
-5
src/gate.rs
···
38
38
redirect_url: Option<String>,
39
39
}
40
40
41
+
/// GET /gate/signup - Display the captcha page
41
-
/// GET /gate - Display the captcha page
42
42
pub async fn get_gate(
43
43
Query(params): Query<GateQuery>,
44
44
State(state): State<AppState>,
···
75
75
.into_response()
76
76
}
77
77
78
+
/// POST /gate/signup - Verify captcha and redirect
78
-
/// POST /gate - Verify captcha and redirect
79
79
pub async fn post_gate(
80
80
State(state): State<AppState>,
81
81
Query(params): Query<GateQuery>,
···
134
134
log::error!("Failed to verify hCaptcha: {}", e);
135
135
136
136
return Redirect::to(&format!(
137
+
"/gate/signup?handle={}&state={}&error={}",
137
-
"/gate?handle={}&state={}&error={}",
138
138
url_encode(¶ms.handle),
139
139
url_encode(¶ms.state),
140
140
url_encode("Verification failed. Please try again.")
···
149
149
log::error!("Failed to parse hCaptcha response: {}", e);
150
150
151
151
return Redirect::to(&format!(
152
+
"/gate/signup?handle={}&state={}&error={}",
152
-
"/gate?handle={}&state={}&error={}",
153
153
url_encode(¶ms.handle),
154
154
url_encode(¶ms.state),
155
155
url_encode("Verification failed. Please try again.")
···
165
165
captcha_result.error_codes
166
166
);
167
167
return Redirect::to(&format!(
168
+
"/gate/signup?handle={}&state={}&error={}",
168
-
"/gate?handle={}&state={}&error={}",
169
169
url_encode(¶ms.handle),
170
170
url_encode(¶ms.state),
171
171
url_encode("Verification failed. Please try again.")
+1
-1
src/helpers.rs
+1
-1
src/helpers.rs
+46
src/mailer.rs
+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
+
}
+8
-7
src/main.rs
+8
-7
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
};
8
+
use anyhow::Result;
7
9
use axum::{
8
10
Router,
9
11
body::Body,
···
18
20
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
19
21
use jacquard_common::types::did::Did;
20
22
use jacquard_identity::{PublicResolver, resolver::PlcSource};
21
-
use lettre::{AsyncSmtpTransport, Tokio1Executor};
22
23
use rand::Rng;
23
24
use rust_embed::RustEmbed;
24
25
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode};
···
30
31
use tower_governor::{
31
32
GovernorLayer, governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor,
32
33
};
34
+
use tower_http::cors::AllowHeaders;
33
35
use tower_http::trace::{DefaultOnRequest, HttpMakeClassifier};
34
36
use tower_http::{
35
37
compression::CompressionLayer,
···
42
44
mod auth;
43
45
mod gate;
44
46
pub mod helpers;
47
+
pub mod mailer;
45
48
mod middleware;
46
49
mod oauth_provider;
47
50
mod xrpc;
···
153
156
account_pool: SqlitePool,
154
157
pds_gatekeeper_pool: SqlitePool,
155
158
reverse_proxy_client: HyperUtilClient,
156
-
mailer: AsyncSmtpTransport<Tokio1Executor>,
159
+
mailer: Arc<Mailer>,
157
160
template_engine: Engine<Handlebars<'static>>,
158
161
resolver: Arc<PublicResolver>,
159
162
handle_cache: auth::HandleCache,
···
216
219
let account_db_url = format!("{pds_root}/account.sqlite");
217
220
218
221
let account_options = SqliteConnectOptions::new()
222
+
.journal_mode(SqliteJournalMode::Wal)
219
223
.filename(account_db_url)
220
224
.busy_timeout(Duration::from_secs(5));
221
225
···
247
251
.build(HttpConnector::new());
248
252
249
253
//Emailer set up
250
-
let smtp_url =
251
-
env::var("PDS_EMAIL_SMTP_URL").expect("PDS_EMAIL_SMTP_URL is not set in your pds.env file");
254
+
let mailer = Arc::new(build_mailer_from_env()?);
252
255
253
-
let mailer: AsyncSmtpTransport<Tokio1Executor> =
254
-
AsyncSmtpTransport::<Tokio1Executor>::from_url(smtp_url.as_str())?.build();
255
256
//Email templates setup
256
257
let mut hbs = Handlebars::new();
257
258
···
355
356
let cors = CorsLayer::new()
356
357
.allow_origin(Any)
357
358
.allow_methods([Method::GET, Method::OPTIONS, Method::POST])
358
-
.allow_headers(Any);
359
+
.allow_headers(AllowHeaders::mirror_request());
359
360
360
361
let mut app = Router::new()
361
362
.route("/", get(root_handler))
+4
-1
src/xrpc/com_atproto_server.rs
+4
-1
src/xrpc/com_atproto_server.rs
···
233
233
.bind(&did_row.0)
234
234
.execute(&state.pds_gatekeeper_pool)
235
235
.await
236
+
.map_err(|err| {
237
+
log::error!("Error enabling 2FA: {err}");
238
+
StatusCode::BAD_REQUEST
239
+
})?;
236
-
.map_err(|_| StatusCode::BAD_REQUEST)?;
237
240
238
241
Ok(StatusCode::OK.into_response())
239
242
}
History
2 rounds
0 comments
baileytownsend.dev
submitted
#1
2 commits
expand
collapse
feat: add opt-in per-request logging
Add GATEKEEPER_REQUEST_LOGGING=true to enable per-request tracing
with method, path, client_ip, status, and latency_ms. Disabled by
default — existing behavior unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
light changes to logging changes
expand 0 comments
pull request successfully merged
baileytownsend.dev
submitted
#0
2 commits
expand
collapse
feat: add opt-in per-request logging
Add GATEKEEPER_REQUEST_LOGGING=true to enable per-request tracing
with method, path, client_ip, status, and latency_ms. Disabled by
default — existing behavior unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
light changes to logging changes