steid

@jamesgill /

steid/src/main.rs
2.4 KBCode·Blame·Raw
1use steid::{
2 application::{AppConfig, is_claimed},
3 domain::SetupToken,
4 infrastructure::{
5 self,
6 repository::SqliteUserRepo,
7 web::{context::SetupState, session_cookie::InsecureCookieTokenStore},
8 },
9};
10use topcoat::{
11 asset::{AssetBundle, RouterBuilderAssetExt},
12 cookie::RouterBuilderCookieExt,
13 router::{Router, RouterBuilderDiscoverExt},
14 session::{RouterBuilderSessionExt, SessionConfig},
15};
16
17#[tokio::main]
18async fn main() -> Result<(), Box<dyn std::error::Error>> {
19 dotenvy::dotenv().ok();
20
21 let config = AppConfig::from_env()?;
22 let pool = infrastructure::database::connect(&config.database_url).await?;
23
24 let mut builder = Router::builder()
25 .assets(AssetBundle::load()?)
26 .cookies()
27 .sessions(session_config(config.insecure_cookies))
28 .discover()
29 .app_context(config)
30 .app_context(pool.clone());
31
32 // The setup token exists only while the instance is unclaimed, so a claimed
33 // installation has no token in context for a claim attempt to match against.
34 if !is_claimed(&SqliteUserRepo::new(pool)).await? {
35 let token = SetupToken::generate();
36 announce_setup(&token);
37 builder = builder.app_context(SetupState(token));
38 }
39
40 topcoat::start(builder.build()).await?;
41
42 Ok(())
43}
44
45/// Builds the session configuration.
46///
47/// The hardened default requires a trustworthy origin for its `Secure` cookie;
48/// browsers disagree about whether plain-HTTP localhost qualifies, and where it
49/// doesn't the cookie is dropped silently and every page renders signed out.
50fn session_config(insecure_cookies: bool) -> SessionConfig {
51 if insecure_cookies {
52 eprintln!();
53 eprintln!(" !! STEID_INSECURE_COOKIES is on: the session cookie has no Secure");
54 eprintln!(" !! flag and travels unencrypted. Local development only.");
55 eprintln!();
56
57 SessionConfig::builder()
58 .token_store(InsecureCookieTokenStore::new())
59 .build()
60 } else {
61 SessionConfig::default()
62 }
63}
64
65/// Prints the claim instructions. The only time the token is ever revealed.
66fn announce_setup(token: &SetupToken) {
67 println!();
68 println!(" This steid has no owner yet. Claim it at /auth/setup with:");
69 println!();
70 println!(" {}", token.reveal());
71 println!();
72 println!(" The token is held in memory only — restarting issues a new one.");
73 println!();
74}