confium_log_server/main.rs
1//! `confium-log-server` — public transparency log server.
2//!
3//! Reference implementation of `log.confium.org`. An append-only
4//! Merkle transparency log (RFC 6962 / RFC 9162) with first-class
5//! support for certificate entries — every Confium-issued cert
6//! (CNML, code-signing, SSH, document-signing, TLS) gets anchored
7//! automatically and is queryable by fingerprint.
8//!
9//! ## Architecture
10//!
11//! Single binary, embedded SQLite storage, no external services to
12//! operate. The Merkle tree is materialized incrementally on each
13//! append; reads serve from in-memory cache.
14//!
15//! ## Quickstart
16//!
17//! ```sh
18//! $ cargo run -p confium-log-server -- --db /var/lib/confium/log.db --listen 0.0.0.0:8080
19//! # listening on http://0.0.0.0:8080
20//! ```
21//!
22//! ## API
23//!
24//! ### Hash entries (generic)
25//!
26//! `POST /v1/append` — append a SHA-256 hash
27//! `GET /v1/head` — current tree head
28//! `GET /v1/proof/<sequence>` — inclusion proof
29//! `GET /v1/consistency/<old_size>` — consistency proof
30//!
31//! ### Certificate entries (cert-aware)
32//!
33//! `POST /v1/certificates` — append a DER-encoded X.509 cert
34//! `GET /v1/certificates/<fingerprint>` — lookup by SHA-256 fingerprint
35//! `GET /v1/issuers/<issuer>/certificates` — list certs by issuer DN
36//!
37//! ### Bitcoin OTS anchoring
38//!
39//! `GET /v1/head/<sequence>/ots` — OTS proof for tree head at sequence
40//!
41//! ### Witness gossip
42//!
43//! `POST /v1/head/<sequence>/witness` — submit a witness countersignature
44//! `GET /v1/head/<sequence>/witnesses` — list known witnesses for tree head
45
46// Several log-server helpers (pagination field, witness digest helpers,
47// historical entry lookup) are pub for the upcoming HTTP API expansion
48// but not yet wired into a route handler.
49#![forbid(unsafe_code)]
50#![allow(dead_code)]
51#![allow(missing_docs)]
52
53mod api;
54mod cert;
55mod db;
56#[cfg(feature = "postgres")]
57mod db_pg;
58mod merkle;
59mod ots_anchor;
60mod witness;
61
62use clap::Parser;
63use std::path::PathBuf;
64use std::sync::Arc;
65
66use api::AppState;
67
68/// Command-line arguments for the log server.
69#[derive(Parser, Debug)]
70#[command(
71 name = "confium-log-server",
72 version,
73 about = "Public transparency log server for Confium"
74)]
75pub struct Args {
76 /// Path to the SQLite database file. Created if missing.
77 #[arg(long, default_value = "confium-log.db")]
78 pub db: PathBuf,
79
80 /// Address to listen on.
81 #[arg(long, default_value = "127.0.0.1:8080")]
82 pub listen: String,
83
84 /// Disable the periodic OTS anchor (useful for testing).
85 #[arg(long)]
86 pub no_ots: bool,
87
88 /// Interval between OTS anchor submissions, in seconds.
89 #[arg(long, default_value_t = 600)]
90 pub ots_interval_secs: u64,
91
92 /// Maximum entries per paged response.
93 #[arg(long, default_value_t = 1000)]
94 pub page_size: usize,
95}
96
97#[tokio::main]
98async fn main() -> Result<(), Box<dyn std::error::Error>> {
99 tracing_subscriber::fmt()
100 .with_env_filter(
101 tracing_subscriber::EnvFilter::try_from_default_env()
102 .unwrap_or_else(|_| "confium_log_server=info,tower_http=info".into()),
103 )
104 .init();
105
106 let args = Args::parse();
107 tracing::info!(?args.db, ?args.listen, "starting confium-log-server");
108
109 let db = db::Database::open(&args.db)?;
110 db.init_schema()?;
111 let merkle = merkle::MerkleState::from_db(&db)?;
112 let state = Arc::new(AppState {
113 db,
114 merkle: parking_lot::Mutex::new(merkle),
115 page_size: args.page_size,
116 });
117
118 // Background OTS anchor task. Skipped when --no-ots is set.
119 if !args.no_ots {
120 let anchor_state = state.clone();
121 tokio::spawn(async move {
122 ots_anchor::run_anchor_loop(
123 anchor_state,
124 std::time::Duration::from_secs(args.ots_interval_secs),
125 )
126 .await;
127 });
128 }
129
130 let app = api::router(state);
131 let listener = tokio::net::TcpListener::bind(&args.listen).await?;
132 tracing::info!("listening on http://{}", args.listen);
133 axum::serve(listener, app).await?;
134 Ok(())
135}