1pub mod admin;
8pub mod error;
9pub mod pairing;
10pub mod routes;
12pub mod store;
13
14use std::sync::Arc;
15
16use axum::{Extension, Router};
17use edda_auth::{
18 DeviceKey,
19 server::{TokenSigner, TokenVerifier},
20};
21use edda_server::{Limits, openapi::Conventions};
22use sqlx::PgPool;
23
24pub use store::Store;
25
26#[derive(utoipa::OpenApi)]
28#[openapi(
29 paths(
30 edda_server::health,
31 edda_server::ready,
32 routes::public_key,
33 routes::lookup_setup_code,
34 routes::setup,
35 routes::challenge,
36 routes::login,
37 routes::campaign,
38 routes::devices,
39 routes::add_device,
40 routes::revoke,
41 pairing::open,
42 pairing::cancel,
43 pairing::send_as_host,
44 pairing::described::receive_from_host,
45 pairing::send_as_joiner,
46 pairing::described::receive_from_joiner,
47 ),
48 modifiers(&Conventions),
49 tags(
50 (name = "auth", description = "Setting up a campaign's first DM device, and logging in."),
51 (name = "devices", description = "A campaign's devices: DM devices add and revoke them."),
52 (name = "pairing", description = "Relaying the messages that pair a new device with a DM's, by a code read out between them."),
53 )
54)]
55pub struct ApiDoc;
56
57pub async fn connect(database_url: &str) -> Result<PgPool, sqlx::Error> {
59 edda_server::open_database(database_url, &sqlx::migrate!()).await
60}
61
62pub async fn app(
66 pool: PgPool,
67 token_key: Option<DeviceKey>,
68 limits: Limits,
69) -> Result<Router, error::ApiError> {
70 let ready = edda_server::readiness(pool.clone());
71 let store = Store::new(pool);
72 let token_key = match token_key {
73 Some(key) => key,
74 None => store.token_key().await?,
75 };
76 let signer = TokenSigner::new(&token_key);
77 let verifier = Arc::new(TokenVerifier::new(signer.public_key()));
78 Ok(Router::new()
79 .merge(routes::router(&limits))
80 .merge(pairing::router(&limits))
81 .with_state(Arc::new(routes::AppState {
82 store,
83 signer,
84 limits,
85 }))
86 .layer(Extension(verifier))
87 .merge(ready))
88}