use anyhow::*; use log::LevelFilter; use northstar::{ GEMINI_PORT, Document, Request, Response, Server, user_management::{ User, UserManagementRoutes, }, }; #[tokio::main] /// An ultra-simple demonstration of authentication. /// /// The user should be able to set a secret string that only they can see. They should be /// able to change this at any time to any thing. Both the string and the user account /// will persist across restarts. /// /// This method sets up and starts the server async fn main() -> Result<()> { // Turn on logging env_logger::builder() .filter_module("northstar", LevelFilter::Debug) .init(); Server::bind(("0.0.0.0", GEMINI_PORT)) // Add our main routes .add_route("/", handle_main) .add_route("/update", handle_update) // Add routes for handling user authentication .add_um_routes::("/") // Start the server .serve() .await } /// The landing page /// /// Displays the user's current secret string, or prompts the user to sign in if they /// haven't. Includes links to update your string (`/update`) or your account /// (`/account`). Even though we haven't added an explicit handler for `/account`, this /// route is managed by northstar. async fn handle_main(request: Request) -> Result { // Check to see if the user is signed in. If they are, we get a copy of their data // (just a simple [`String`] for this demo, but this can be any serializable struct. if let User::SignedIn(user) = request.user::()? { // If the user is signed in, render and return their page let response = Document::new() .add_text("Your personal secret string:") .add_text(user.as_ref()) .add_blank_line() .add_link("/update", "Change your string") .add_link("/account", "Update your account") .into(); Ok(response) } else { // If the user is not logged in, prompt them to go to /account let response = Document::new() .add_text("Please login to use this app.") .add_blank_line() .add_link("/account", "Login or create account") .into(); Ok(response) } } /// The update endpoint /// /// Users can update their secret string here. Users who haven't logged in will be /// promped to do so. async fn handle_update(request: Request) -> Result { // Check if the user is signed in again if let User::SignedIn(mut user) = request.user::()? { // If the user is logged in, check to see if they provided any input. If they // have, we can set that input as their new string, otherwise we ask them for it if let Some(string) = request.input() { // Update the users data *user.as_mut() = string.to_owned(); // Render a response let response = Document::new() .add_text("String updated!") .add_blank_line() .add_link("/", "Back") .into(); Ok(response) } else { // Ask the user for some input Ok(Response::input_lossy("Enter your new string")) } } else { // The user isn't logged in, so we should ask them too let response = Document::new() .add_text("Please login to use this app.") .add_blank_line() .add_link("/account", "Login or create account") .into(); Ok(response) } }