2025-03-12 12:32:15 -07:00
/*
* 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 < https ://www.gnu.org/licenses/>.
* /
mod register ;
mod verify ;
mod login ;
use std ::{ env , process } ;
use std ::collections ::HashMap ;
2025-09-04 15:53:53 +12:00
use std ::net ::{ SocketAddr , ToSocketAddrs } ;
2025-03-12 12:32:15 -07:00
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 < Url > ,
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) " ) ,
2025-09-04 15:53:53 +12:00
nats_addr : env ::var ( " NATS_ADDR " ) . unwrap_or ( " 127.0.0.1:4222 " . to_string ( ) ) . to_socket_addrs ( ) . expect ( " Badly formed NATS_ADDR (Needs to be SocketAddr) " ) . nth ( 0 ) . unwrap ( ) ,
2025-03-12 12:32:15 -07:00
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 " ) ;
}