this repo has no description
1pub mod api;
2pub mod appview;
3pub mod auth;
4pub mod cache;
5pub mod circuit_breaker;
6pub mod comms;
7pub mod config;
8pub mod crawlers;
9pub mod delegation;
10pub mod handle;
11pub mod image;
12pub mod metrics;
13pub mod moderation;
14pub mod oauth;
15pub mod plc;
16pub mod rate_limit;
17pub mod repo;
18pub mod scheduled;
19pub mod state;
20pub mod storage;
21pub mod sync;
22pub mod types;
23pub mod util;
24pub mod validation;
25
26use api::proxy::XrpcProxyLayer;
27pub use sync::util::AccountStatus;
28pub use types::{AccountState, AtIdentifier, AtUri, Did, Handle, Nsid, Rkey};
29use axum::{
30 Json, Router,
31 extract::DefaultBodyLimit,
32 http::Method,
33 middleware,
34 routing::{get, post},
35};
36use http::StatusCode;
37use serde_json::json;
38use state::AppState;
39use tower::ServiceBuilder;
40use tower_http::cors::{Any, CorsLayer};
41use tower_http::services::{ServeDir, ServeFile};
42
43pub fn app(state: AppState) -> Router {
44 let xrpc_router = Router::new()
45 .route("/_health", get(api::server::health))
46 .route(
47 "/com.atproto.server.describeServer",
48 get(api::server::describe_server),
49 )
50 .route(
51 "/com.atproto.server.createAccount",
52 post(api::identity::create_account),
53 )
54 .route(
55 "/com.atproto.server.createSession",
56 post(api::server::create_session),
57 )
58 .route(
59 "/com.atproto.server.getSession",
60 get(api::server::get_session),
61 )
62 .route("/_account.listSessions", get(api::server::list_sessions))
63 .route("/_account.revokeSession", post(api::server::revoke_session))
64 .route(
65 "/_account.revokeAllSessions",
66 post(api::server::revoke_all_sessions),
67 )
68 .route(
69 "/com.atproto.server.deleteSession",
70 post(api::server::delete_session),
71 )
72 .route(
73 "/com.atproto.server.refreshSession",
74 post(api::server::refresh_session),
75 )
76 .route(
77 "/com.atproto.server.confirmSignup",
78 post(api::server::confirm_signup),
79 )
80 .route(
81 "/com.atproto.server.resendVerification",
82 post(api::server::resend_verification),
83 )
84 .route(
85 "/com.atproto.server.getServiceAuth",
86 get(api::server::get_service_auth),
87 )
88 .route(
89 "/com.atproto.identity.resolveHandle",
90 get(api::identity::resolve_handle),
91 )
92 .route(
93 "/com.atproto.repo.createRecord",
94 post(api::repo::create_record),
95 )
96 .route("/com.atproto.repo.putRecord", post(api::repo::put_record))
97 .route("/com.atproto.repo.getRecord", get(api::repo::get_record))
98 .route(
99 "/com.atproto.repo.deleteRecord",
100 post(api::repo::delete_record),
101 )
102 .route(
103 "/com.atproto.repo.listRecords",
104 get(api::repo::list_records),
105 )
106 .route(
107 "/com.atproto.repo.describeRepo",
108 get(api::repo::describe_repo),
109 )
110 .route("/com.atproto.repo.uploadBlob", post(api::repo::upload_blob))
111 .route(
112 "/com.atproto.repo.applyWrites",
113 post(api::repo::apply_writes),
114 )
115 .route(
116 "/com.atproto.sync.getLatestCommit",
117 get(sync::get_latest_commit),
118 )
119 .route("/com.atproto.sync.listRepos", get(sync::list_repos))
120 .route("/com.atproto.sync.getBlob", get(sync::get_blob))
121 .route("/com.atproto.sync.listBlobs", get(sync::list_blobs))
122 .route(
123 "/com.atproto.sync.getRepoStatus",
124 get(sync::get_repo_status),
125 )
126 .route(
127 "/com.atproto.server.checkAccountStatus",
128 get(api::server::check_account_status),
129 )
130 .route(
131 "/com.atproto.identity.getRecommendedDidCredentials",
132 get(api::identity::get_recommended_did_credentials),
133 )
134 .route(
135 "/com.atproto.repo.listMissingBlobs",
136 get(api::repo::list_missing_blobs),
137 )
138 .route(
139 "/com.atproto.sync.notifyOfUpdate",
140 post(sync::notify_of_update),
141 )
142 .route("/com.atproto.sync.requestCrawl", post(sync::request_crawl))
143 .route("/com.atproto.sync.getBlocks", get(sync::get_blocks))
144 .route("/com.atproto.sync.getRepo", get(sync::get_repo))
145 .route("/com.atproto.sync.getRecord", get(sync::get_record))
146 .route(
147 "/com.atproto.sync.subscribeRepos",
148 get(sync::subscribe_repos),
149 )
150 .route("/com.atproto.sync.getHead", get(sync::get_head))
151 .route("/com.atproto.sync.getCheckout", get(sync::get_checkout))
152 .route(
153 "/com.atproto.moderation.createReport",
154 post(api::moderation::create_report),
155 )
156 .route(
157 "/com.atproto.admin.getAccountInfo",
158 get(api::admin::get_account_info),
159 )
160 .route(
161 "/com.atproto.admin.getAccountInfos",
162 get(api::admin::get_account_infos),
163 )
164 .route(
165 "/com.atproto.admin.searchAccounts",
166 get(api::admin::search_accounts),
167 )
168 .route(
169 "/com.atproto.server.activateAccount",
170 post(api::server::activate_account),
171 )
172 .route(
173 "/com.atproto.server.deactivateAccount",
174 post(api::server::deactivate_account),
175 )
176 .route(
177 "/com.atproto.server.requestAccountDelete",
178 post(api::server::request_account_delete),
179 )
180 .route(
181 "/com.atproto.server.deleteAccount",
182 post(api::server::delete_account),
183 )
184 .route(
185 "/com.atproto.server.requestPasswordReset",
186 post(api::server::request_password_reset),
187 )
188 .route(
189 "/com.atproto.server.resetPassword",
190 post(api::server::reset_password),
191 )
192 .route(
193 "/_account.changePassword",
194 post(api::server::change_password),
195 )
196 .route(
197 "/_account.removePassword",
198 post(api::server::remove_password),
199 )
200 .route(
201 "/_account.getPasswordStatus",
202 get(api::server::get_password_status),
203 )
204 .route(
205 "/_account.getReauthStatus",
206 get(api::server::get_reauth_status),
207 )
208 .route(
209 "/_account.reauthPassword",
210 post(api::server::reauth_password),
211 )
212 .route("/_account.reauthTotp", post(api::server::reauth_totp))
213 .route(
214 "/_account.reauthPasskeyStart",
215 post(api::server::reauth_passkey_start),
216 )
217 .route(
218 "/_account.reauthPasskeyFinish",
219 post(api::server::reauth_passkey_finish),
220 )
221 .route(
222 "/_account.getLegacyLoginPreference",
223 get(api::server::get_legacy_login_preference),
224 )
225 .route(
226 "/_account.updateLegacyLoginPreference",
227 post(api::server::update_legacy_login_preference),
228 )
229 .route("/_account.updateLocale", post(api::server::update_locale))
230 .route(
231 "/_account.listTrustedDevices",
232 get(api::server::list_trusted_devices),
233 )
234 .route(
235 "/_account.revokeTrustedDevice",
236 post(api::server::revoke_trusted_device),
237 )
238 .route(
239 "/_account.updateTrustedDevice",
240 post(api::server::update_trusted_device),
241 )
242 .route(
243 "/_account.createPasskeyAccount",
244 post(api::server::create_passkey_account),
245 )
246 .route(
247 "/_account.startPasskeyRegistrationForSetup",
248 post(api::server::start_passkey_registration_for_setup),
249 )
250 .route(
251 "/_account.completePasskeySetup",
252 post(api::server::complete_passkey_setup),
253 )
254 .route(
255 "/_account.requestPasskeyRecovery",
256 post(api::server::request_passkey_recovery),
257 )
258 .route(
259 "/_account.recoverPasskeyAccount",
260 post(api::server::recover_passkey_account),
261 )
262 .route(
263 "/_account.updateDidDocument",
264 post(api::server::update_did_document),
265 )
266 .route(
267 "/_account.getDidDocument",
268 get(api::server::get_did_document),
269 )
270 .route(
271 "/com.atproto.server.requestEmailUpdate",
272 post(api::server::request_email_update),
273 )
274 .route(
275 "/_checkEmailVerified",
276 post(api::server::check_email_verified),
277 )
278 .route(
279 "/com.atproto.server.confirmEmail",
280 post(api::server::confirm_email),
281 )
282 .route(
283 "/com.atproto.server.updateEmail",
284 post(api::server::update_email),
285 )
286 .route(
287 "/com.atproto.server.reserveSigningKey",
288 post(api::server::reserve_signing_key),
289 )
290 .route(
291 "/com.atproto.server.verifyMigrationEmail",
292 post(api::server::verify_migration_email),
293 )
294 .route(
295 "/com.atproto.server.resendMigrationVerification",
296 post(api::server::resend_migration_verification),
297 )
298 .route(
299 "/com.atproto.identity.updateHandle",
300 post(api::identity::update_handle),
301 )
302 .route(
303 "/com.atproto.identity.requestPlcOperationSignature",
304 post(api::identity::request_plc_operation_signature),
305 )
306 .route(
307 "/com.atproto.identity.signPlcOperation",
308 post(api::identity::sign_plc_operation),
309 )
310 .route(
311 "/com.atproto.identity.submitPlcOperation",
312 post(api::identity::submit_plc_operation),
313 )
314 .route("/com.atproto.repo.importRepo", post(api::repo::import_repo))
315 .route(
316 "/com.atproto.admin.deleteAccount",
317 post(api::admin::delete_account),
318 )
319 .route(
320 "/com.atproto.admin.updateAccountEmail",
321 post(api::admin::update_account_email),
322 )
323 .route(
324 "/com.atproto.admin.updateAccountHandle",
325 post(api::admin::update_account_handle),
326 )
327 .route(
328 "/com.atproto.admin.updateAccountPassword",
329 post(api::admin::update_account_password),
330 )
331 .route(
332 "/com.atproto.server.listAppPasswords",
333 get(api::server::list_app_passwords),
334 )
335 .route(
336 "/com.atproto.server.createAppPassword",
337 post(api::server::create_app_password),
338 )
339 .route(
340 "/com.atproto.server.revokeAppPassword",
341 post(api::server::revoke_app_password),
342 )
343 .route(
344 "/com.atproto.server.createInviteCode",
345 post(api::server::create_invite_code),
346 )
347 .route(
348 "/com.atproto.server.createInviteCodes",
349 post(api::server::create_invite_codes),
350 )
351 .route(
352 "/com.atproto.server.getAccountInviteCodes",
353 get(api::server::get_account_invite_codes),
354 )
355 .route(
356 "/com.atproto.server.createTotpSecret",
357 post(api::server::create_totp_secret),
358 )
359 .route(
360 "/com.atproto.server.enableTotp",
361 post(api::server::enable_totp),
362 )
363 .route(
364 "/com.atproto.server.disableTotp",
365 post(api::server::disable_totp),
366 )
367 .route(
368 "/com.atproto.server.getTotpStatus",
369 get(api::server::get_totp_status),
370 )
371 .route(
372 "/com.atproto.server.regenerateBackupCodes",
373 post(api::server::regenerate_backup_codes),
374 )
375 .route(
376 "/com.atproto.server.startPasskeyRegistration",
377 post(api::server::start_passkey_registration),
378 )
379 .route(
380 "/com.atproto.server.finishPasskeyRegistration",
381 post(api::server::finish_passkey_registration),
382 )
383 .route(
384 "/com.atproto.server.listPasskeys",
385 get(api::server::list_passkeys),
386 )
387 .route(
388 "/com.atproto.server.deletePasskey",
389 post(api::server::delete_passkey),
390 )
391 .route(
392 "/com.atproto.server.updatePasskey",
393 post(api::server::update_passkey),
394 )
395 .route(
396 "/com.atproto.admin.getInviteCodes",
397 get(api::admin::get_invite_codes),
398 )
399 .route("/_admin.getServerStats", get(api::admin::get_server_stats))
400 .route("/_server.getConfig", get(api::admin::get_server_config))
401 .route(
402 "/_admin.updateServerConfig",
403 post(api::admin::update_server_config),
404 )
405 .route(
406 "/com.atproto.admin.disableAccountInvites",
407 post(api::admin::disable_account_invites),
408 )
409 .route(
410 "/com.atproto.admin.enableAccountInvites",
411 post(api::admin::enable_account_invites),
412 )
413 .route(
414 "/com.atproto.admin.disableInviteCodes",
415 post(api::admin::disable_invite_codes),
416 )
417 .route(
418 "/com.atproto.admin.getSubjectStatus",
419 get(api::admin::get_subject_status),
420 )
421 .route(
422 "/com.atproto.admin.updateSubjectStatus",
423 post(api::admin::update_subject_status),
424 )
425 .route("/com.atproto.admin.sendEmail", post(api::admin::send_email))
426 .route(
427 "/app.bsky.actor.getPreferences",
428 get(api::actor::get_preferences),
429 )
430 .route(
431 "/app.bsky.actor.putPreferences",
432 post(api::actor::put_preferences),
433 )
434 .route(
435 "/com.atproto.temp.checkSignupQueue",
436 get(api::temp::check_signup_queue),
437 )
438 .route(
439 "/com.atproto.temp.dereferenceScope",
440 post(api::temp::dereference_scope),
441 )
442 .route(
443 "/_account.getNotificationPrefs",
444 get(api::notification_prefs::get_notification_prefs),
445 )
446 .route(
447 "/_account.updateNotificationPrefs",
448 post(api::notification_prefs::update_notification_prefs),
449 )
450 .route(
451 "/_account.getNotificationHistory",
452 get(api::notification_prefs::get_notification_history),
453 )
454 .route(
455 "/_account.confirmChannelVerification",
456 post(api::verification::confirm_channel_verification),
457 )
458 .route("/_account.verifyToken", post(api::server::verify_token))
459 .route(
460 "/_delegation.listControllers",
461 get(api::delegation::list_controllers),
462 )
463 .route(
464 "/_delegation.addController",
465 post(api::delegation::add_controller),
466 )
467 .route(
468 "/_delegation.removeController",
469 post(api::delegation::remove_controller),
470 )
471 .route(
472 "/_delegation.updateControllerScopes",
473 post(api::delegation::update_controller_scopes),
474 )
475 .route(
476 "/_delegation.listControlledAccounts",
477 get(api::delegation::list_controlled_accounts),
478 )
479 .route(
480 "/_delegation.getAuditLog",
481 get(api::delegation::get_audit_log),
482 )
483 .route(
484 "/_delegation.getScopePresets",
485 get(api::delegation::get_scope_presets),
486 )
487 .route(
488 "/_delegation.createDelegatedAccount",
489 post(api::delegation::create_delegated_account),
490 )
491 .route("/_backup.listBackups", get(api::backup::list_backups))
492 .route("/_backup.getBackup", get(api::backup::get_backup))
493 .route("/_backup.createBackup", post(api::backup::create_backup))
494 .route("/_backup.deleteBackup", post(api::backup::delete_backup))
495 .route("/_backup.setEnabled", post(api::backup::set_backup_enabled))
496 .route("/_backup.exportBlobs", get(api::backup::export_blobs))
497 .route(
498 "/app.bsky.ageassurance.getState",
499 get(api::age_assurance::get_state),
500 )
501 .route(
502 "/app.bsky.unspecced.getAgeAssuranceState",
503 get(api::age_assurance::get_age_assurance_state),
504 )
505 .fallback(async || (
506 StatusCode::NOT_IMPLEMENTED,
507 Json(json!({"error": "MethodNotImplemented", "message": "XRPC method not implemented"})),
508 ));
509 let xrpc_service = ServiceBuilder::new()
510 .layer(XrpcProxyLayer::new(state.clone()))
511 .service(xrpc_router.with_state(state.clone()));
512
513 let oauth_router = Router::new()
514 .route("/jwks", get(oauth::endpoints::oauth_jwks))
515 .route(
516 "/client-metadata.json",
517 get(oauth::endpoints::frontend_client_metadata),
518 )
519 .route("/par", post(oauth::endpoints::pushed_authorization_request))
520 .route("/authorize", get(oauth::endpoints::authorize_get))
521 .route("/authorize", post(oauth::endpoints::authorize_post))
522 .route(
523 "/authorize/accounts",
524 get(oauth::endpoints::authorize_accounts),
525 )
526 .route(
527 "/authorize/select",
528 post(oauth::endpoints::authorize_select),
529 )
530 .route("/authorize/2fa", get(oauth::endpoints::authorize_2fa_get))
531 .route("/authorize/2fa", post(oauth::endpoints::authorize_2fa_post))
532 .route(
533 "/authorize/passkey",
534 get(oauth::endpoints::authorize_passkey_start),
535 )
536 .route(
537 "/authorize/passkey",
538 post(oauth::endpoints::authorize_passkey_finish),
539 )
540 .route(
541 "/passkey/check",
542 get(oauth::endpoints::check_user_has_passkeys),
543 )
544 .route(
545 "/security-status",
546 get(oauth::endpoints::check_user_security_status),
547 )
548 .route("/passkey/start", post(oauth::endpoints::passkey_start))
549 .route("/passkey/finish", post(oauth::endpoints::passkey_finish))
550 .route("/authorize/deny", post(oauth::endpoints::authorize_deny))
551 .route("/authorize/consent", get(oauth::endpoints::consent_get))
552 .route("/authorize/consent", post(oauth::endpoints::consent_post))
553 .route("/delegation/auth", post(oauth::endpoints::delegation_auth))
554 .route(
555 "/delegation/totp",
556 post(oauth::endpoints::delegation_totp_verify),
557 )
558 .route("/token", post(oauth::endpoints::token_endpoint))
559 .route("/revoke", post(oauth::endpoints::revoke_token))
560 .route("/introspect", post(oauth::endpoints::introspect_token));
561
562 let well_known_router = Router::new()
563 .route("/did.json", get(api::identity::well_known_did))
564 .route("/atproto-did", get(api::identity::well_known_atproto_did))
565 .route(
566 "/oauth-protected-resource",
567 get(oauth::endpoints::oauth_protected_resource),
568 )
569 .route(
570 "/oauth-authorization-server",
571 get(oauth::endpoints::oauth_authorization_server),
572 );
573
574 let router = Router::new()
575 .nest_service("/xrpc", xrpc_service)
576 .nest("/oauth", oauth_router)
577 .nest("/.well-known", well_known_router)
578 .route("/metrics", get(metrics::metrics_handler))
579 .route("/health", get(api::server::health))
580 .route("/robots.txt", get(api::server::robots_txt))
581 .route("/logo", get(api::server::get_logo))
582 .route("/u/{handle}/did.json", get(api::identity::user_did_doc))
583 .layer(DefaultBodyLimit::max(util::get_max_blob_size()))
584 .layer(middleware::from_fn(metrics::metrics_middleware))
585 .layer(
586 CorsLayer::new()
587 .allow_origin(Any)
588 .allow_methods([Method::GET, Method::POST, Method::OPTIONS])
589 .allow_headers(Any),
590 )
591 .with_state(state);
592
593 let frontend_dir =
594 std::env::var("FRONTEND_DIR").unwrap_or_else(|_| "./frontend/dist".to_string());
595 if std::path::Path::new(&frontend_dir)
596 .join("index.html")
597 .exists()
598 {
599 let index_path = format!("{}/index.html", frontend_dir);
600 let homepage_path = format!("{}/homepage.html", frontend_dir);
601
602 let homepage_exists = std::path::Path::new(&homepage_path).exists();
603 let homepage_file = if homepage_exists {
604 homepage_path
605 } else {
606 index_path.clone()
607 };
608
609 let spa_router = Router::new().fallback_service(ServeFile::new(&index_path));
610
611 let serve_dir = ServeDir::new(&frontend_dir).not_found_service(ServeFile::new(&index_path));
612
613 return router
614 .route_service("/", ServeFile::new(&homepage_file))
615 .nest("/app", spa_router)
616 .fallback_service(serve_dir);
617 }
618
619 router
620}