/* * asklyphe-auth-frontend main.rs * - entrypoint for the asklyphe authentication frontend * * Copyright (C) 2025 Real Microsoft, LLC * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ mod register; mod verify; mod login; use std::{env, process}; use std::collections::HashMap; use std::net::SocketAddr; use std::ops::Deref; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Duration; use argon2::{Argon2, PasswordHasher}; use argon2::password_hash::rand_core::OsRng; use argon2::password_hash::SaltString; use askama::Template; use asklyphe_common::nats; use asklyphe_common::nats::authservice::{AuthServiceQuery, AuthServiceRequest, AuthServiceResponse, EmailError, PasswordError, RegisterError, RegisterRequest, RegisterResponse, UsernameError}; use asklyphe_common::nats::comms; use asklyphe_common::nats::comms::ServiceResponse; use async_nats::jetstream; use axum::{Extension, Form, Router}; use axum::extract::Query; use axum::response::IntoResponse; use axum::routing::get; use serde::Deserialize; use tokio::sync::Mutex; use tracing::error; use tracing_loki::url::Url; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use crate::login::{login_get, login_post}; use crate::register::{register_get, register_post}; use crate::verify::verify_get; const VERSION: &str = env!("CARGO_PKG_VERSION"); const GIT_COMMIT: &str = env!("GIT_COMMIT"); const BUILT_ON: &str = env!("BUILT_ON"); const YEAR: &str = env!("YEAR"); #[derive(Clone)] struct Opts { bind_addr: SocketAddr, nats_addr: SocketAddr, nats_cert: String, nats_key: String, asklyphe_url: String, loki_addr: Option, datacenter_id: i64, } #[tokio::main] async fn main() { env_logger::init(); let opts = Opts { bind_addr: env::var("BIND_ADDR").unwrap_or("0.0.0.0:5843".to_string()).parse().expect("Badly formed BIND_ADDR (Needs to be SocketAddr)"), nats_addr: env::var("NATS_ADDR").unwrap_or("127.0.0.1:4222".to_string()).parse().expect("Badly formed NATS_ADDR (Needs to be SocketAddr)"), nats_cert: env::var("NATS_CERT").expect("NATS_CERT needs to be set"), nats_key: env::var("NATS_KEY").expect("NATS_KEY needs to be set"), asklyphe_url: env::var("ASKLYPHE_URL").unwrap_or("https://asklyphe.com".to_string()), loki_addr: match env::var("LOKI_ADDR") { Ok(url) => { Some(Url::parse(&url).expect("Badly formed LOKI_ADDR (Needs to be Url)")) } Err(_) => { None } }, datacenter_id: env::var("DATACENTER_ID").unwrap_or("1".to_string()).parse().expect("Badly formed DATACENTER_ID (Need to be i64)"), }; //if opts.loki_addr.is_some() { // let (layer, task) = tracing_loki::builder() // .label("environment", "dev").unwrap() // .extra_field("pid", process::id().to_string()).unwrap() // .extra_field("run_id", snowflake_factory.generate().to_string()).unwrap() // .build_url(opts.loki_addr.clone().unwrap()).unwrap(); // // Register Loki layer // tracing_subscriber::registry() // .with(layer) // .init(); // // Spawn Loki background task // tokio::spawn(task); //} else { // tracing_subscriber::fmt::init() //} let nats = async_nats::ConnectOptions::new() .add_client_certificate(opts.nats_cert.as_str().into(), opts.nats_key.as_str().into()) .connect(opts.nats_addr.to_string()) .await; if let Err(e) = nats { eprintln!("FATAL ERROR, COULDN'T CONNECT TO NATS: {}", e); return; } let nats = nats.unwrap(); let nats = jetstream::new(nats); let nats = Arc::new(Mutex::new(nats)); let app = Router::new() .route("/register", get(register_get).post(register_post)) .route("/login", get(login_get).post(login_post)) .route("/verify", get(verify_get)) .layer(Extension(nats.clone())) .layer(Extension(opts.clone())); let listener = tokio::net::TcpListener::bind(opts.bind_addr).await.expect("Failed to get listener"); axum::serve(listener, app).await.expect("Failed to serve"); }