2022-09-12 02:14:52 -04:00
#[ macro_use ] extern crate log ;
2022-09-14 03:58:54 -04:00
use std ::{ env , fs } ;
2022-09-12 02:14:52 -04:00
use std ::net ::SocketAddr ;
use std ::path ::Path ;
use axum ::extract ::Extension ;
use axum ::Router ;
use axum ::routing ::{ delete , get , post } ;
use dotenv ::dotenv ;
2022-09-13 09:16:28 -04:00
use lapin ::ConnectionProperties ;
2022-09-14 03:58:54 -04:00
use picky ::key ::PrivateKey ;
2022-09-14 09:03:43 -04:00
use picky ::x509 ::Cert ;
use sea_orm ::{ ActiveValue , ColumnTrait , ConnectOptions , Database , EntityTrait , QueryFilter } ;
2022-09-12 02:14:52 -04:00
use sea_orm_migration ::prelude ::* ;
use tower ::ServiceBuilder ;
2022-09-14 09:03:43 -04:00
use ulid ::Ulid ;
use crate ::cert ::encrypt_priv_key ;
use crate ::cert ::generate ::{ generate_inter_cert , generate_root_cert } ;
use crate ::cert ::generate ::InterTarget ::{ CLIENT , PROXY } ;
use crate ::cert ::Types ::{ CLIENTINTER , PROXYINTER , ROOT } ;
use crate ::certificate ::Model ;
use crate ::entities ::certificate ;
2022-09-12 02:14:52 -04:00
mod entities ;
mod dns ;
mod util ;
mod routes ;
2022-09-12 03:55:10 -04:00
mod rpc ;
2022-09-14 09:03:43 -04:00
mod cert ;
2022-09-12 02:14:52 -04:00
const VERSION : & str = env! ( " CARGO_PKG_VERSION " ) ;
#[ tokio::main ]
async fn main ( ) {
2022-10-11 22:07:27 -04:00
console_subscriber ::init ( ) ;
2022-09-12 02:14:52 -04:00
dotenv ( ) . ok ( ) ;
// Default to logging all info logs
if env ::var ( " RUST_LOG " ) . is_err ( ) {
env ::set_var ( " RUST_LOG " , " info " )
}
2022-10-11 22:07:27 -04:00
//pretty_env_logger::init();
2022-09-12 02:14:52 -04:00
info! ( " ██████╗ ██████╗ ██╗██████╗ ████████╗ ██████╗ ██████╗ ██████╗██╗ ██╗ " ) ;
info! ( " ██╔══██╗██╔══██╗██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝██║ ██║ " ) ;
info! ( " ██║ ██║██████╔╝██║██████╔╝ ██║ ██║ ██║██████╔╝██║ ███████║ " ) ;
info! ( " ██║ ██║██╔══██╗██║██╔═══╝ ██║ ██║ ██║██╔══██╗██║ ██╔══██║ " ) ;
info! ( " ██████╔╝██║ ██║██║██║ ██║ ╚██████╔╝██║ ██║╚██████╗██║ ██║ " ) ;
info! ( " ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ " ) ;
info! ( " ._______ ._______ .______ _____._.______ ._______ .___ .___ ._______.______ " ) ;
info! ( " :_. ___ \\ : .___ \\ : \\ \\ __ _:|: __ \\ : .___ \\ | | | | : .____/: __ \\ " ) ;
info! ( " | : |/ \\ | : | || | | :|| \\ ____|| : | || | | | | : _/ \\ | \\ ____| " ) ;
info! ( " | / \\ | : || | | | || : \\ | : || |/ \\ | |/ \\ | / \\ | : \\ " ) ;
info! ( " |. _____/ \\ _. ___/ |___| | | || |___ \\ \\ _. ___/ | / \\ | / \\ |_.: __/| |___ \\ " ) ;
info! ( " :/ :/ |___| |___||___| :/ |______/|______/ :/ |___| " ) ;
info! ( " : : : " ) ;
info! ( " Version {} " , VERSION ) ;
info! ( " Checking for supplemental files... " ) ;
if ! Path ::new ( & env ::var ( " UAP_REGEXES " ) . unwrap_or ( String ::from ( " ./regexes.yaml " ) ) ) . exists ( ) {
error! ( " Please download https://github.com/ua-parser/uap-core/blob/master/regexes.yaml either place it next to the executable or add it's path to env variable UAP_REGEXES! Halting start-up. " ) ;
std ::process ::exit ( 1 ) ;
}
2022-09-14 03:58:54 -04:00
if ! Path ::new ( & env ::var ( " RSA_KEY " ) . expect ( " RSA_KEY must be set! Halting start-up. " ) ) . exists ( ) {
error! ( " Please generate an RSA private key for creating certificates! " )
}
2022-09-14 09:03:43 -04:00
if ! Path ::new ( & env ::var ( " XCC20_KEY " ) . expect ( " XCC20_KEY must be set! Halting start-up. " ) ) . exists ( ) {
error! ( " Please generate a 32 bits of randomness to encrypt private keys! " )
}
2022-09-14 03:58:54 -04:00
let root_rsa_key = PrivateKey ::from_pem_str (
& * fs ::read_to_string (
Path ::new ( & env ::var ( " RSA_KEY " ) . expect ( " RSA_KEY must be set! Halting start-up. " ) )
) . expect ( " Failed to load the root RSA key! Halting start-up. " )
) . expect ( " Failed to load the root RSA key! Halting start-up. " ) ;
2022-09-12 02:14:52 -04:00
info! ( " Connecting to database... " ) ;
let database_url = env ::var ( " DATABASE_URL " )
. expect ( " DATABASE_URL must be set! Halting start-up. " ) ;
let connection = Database ::connect (
ConnectOptions ::new ( database_url ) . sqlx_logging ( false ) . to_owned ( ) )
. await
. expect ( " Failed to connect to the database! Halting start-up. " ) ;
info! ( " Running migrations... " ) ;
migration ::Migrator ::up ( & connection , None )
. await
. expect ( " Failed to run migrations! Halting start-up. " ) ;
2022-09-14 09:03:43 -04:00
info! ( " Checking for root cert... " ) ;
let root_cert_model : Option < Model > = certificate ::Entity ::find ( )
. filter ( certificate ::Column ::CertType . eq ( cert ::Types ::ROOT . to_string ( ) ) )
. one ( & connection )
. await
. expect ( " Failed to retrieve the root cert from the database! Halting start-up. " ) ;
let root_cert : Cert ;
match root_cert_model {
None = > {
info! ( " Generating new root cert... " ) ;
let new_root_cert = generate_root_cert ( & root_rsa_key )
. await
. expect ( " Failed to generate the root cert from private key! Halting start-up. " ) ;
root_cert = new_root_cert . clone ( ) ;
let root_insert = certificate ::Entity ::insert ( certificate ::ActiveModel {
id : ActiveValue ::Set ( Ulid ::new ( ) . to_string ( ) ) ,
data : ActiveValue ::Set (
new_root_cert . to_der ( ) . expect ( " Failed to convert cert into der! " )
) ,
key : ActiveValue ::set ( vec! [ 145 , 66 , 62 , 61 , 56 , 156 , 145 , 164 ] ) ,
nonce : ActiveValue ::set ( vec! [ 145 , 71 , 62 , 66 , 56 , 156 , 145 , 164 ] ) ,
cert_type : ActiveValue ::Set ( ROOT . to_string ( ) )
} )
. exec ( & connection )
. await
. expect ( " Failed to insert new root cert into database! Halting start-up. " ) ;
info! ( " Generated new root cert: {} " , root_insert . last_insert_id ) ;
}
Some ( root_cert_model ) = > {
info! ( " Found root cert: {} " , root_cert_model . id ) ;
root_cert = Cert ::from_der ( & root_cert_model . data )
. expect ( " Failed to decode root cert! " ) ;
}
}
info! ( " Checking for proxy intermediate cert... " ) ;
let proxy_inter_model : Option < Model > = certificate ::Entity ::find ( )
. filter ( certificate ::Column ::CertType . eq ( PROXYINTER . to_string ( ) ) )
. one ( & connection )
. await
. expect ( " Failed to retrieve the proxy intermediate cert from the database! Halting start-up. " ) ;
let proxy_inter_cert : Cert ;
match proxy_inter_model {
None = > {
info! ( " Generating proxy intermediate cert... " ) ;
// Generate 4096 bit RSA private key
let priv_key = PrivateKey ::generate_rsa ( 4096 )
. expect ( " Failed to generate a key " ) ;
let encrypted_priv_key = encrypt_priv_key ( priv_key
. clone ( )
. to_pkcs8 ( )
. expect ( " Failed to convert generated private key to pkcs8! " )
) . await ;
let new_proxy_inter_cert = generate_inter_cert ( & priv_key , PROXY , ( & root_cert , & root_rsa_key ) )
. await
. expect ( " Failed to generate new proxy intermediate cert " ) ;
proxy_inter_cert = new_proxy_inter_cert . clone ( ) ;
let proxy_inter_insert = certificate ::Entity ::insert ( certificate ::ActiveModel {
id : ActiveValue ::Set ( Ulid ::new ( ) . to_string ( ) ) ,
data : ActiveValue ::Set (
new_proxy_inter_cert . to_der ( ) . expect ( " Failed to convert cert into der! " )
) ,
key : ActiveValue ::set ( encrypted_priv_key . 1 ) ,
nonce : ActiveValue ::set ( encrypted_priv_key . 0 ) ,
cert_type : ActiveValue ::Set ( PROXYINTER . to_string ( ) )
} )
. exec ( & connection )
. await
. expect ( " Failed to insert new proxy intermediate cert into database! Halting start-up. " ) ;
info! ( " Generated new proxy intermediate cert: {} " , proxy_inter_insert . last_insert_id )
}
Some ( proxy_inter_model ) = > {
info! ( " Found proxy intermediate cert: {} " , proxy_inter_model . id ) ;
proxy_inter_cert = Cert ::from_der ( & proxy_inter_model . data )
. expect ( " Failed to decode proxy intermediate cert! " ) ;
}
}
info! ( " Checking for client intermediate cert... " ) ;
let client_inter_model : Option < Model > = certificate ::Entity ::find ( )
. filter ( certificate ::Column ::CertType . eq ( CLIENTINTER . to_string ( ) ) )
. one ( & connection )
. await
. expect ( " Failed to retrieve the client intermediate cert from the database! Halting start-up. " ) ;
let client_inter_cert : Cert ;
match client_inter_model {
None = > {
info! ( " Generating client intermediate cert... " ) ;
// Generate 4096 bit RSA private key
let priv_key = PrivateKey ::generate_rsa ( 4096 )
. expect ( " Failed to generate a key " ) ;
let encrypted_priv_key = encrypt_priv_key ( priv_key
. clone ( )
. to_pkcs8 ( )
. expect ( " Failed to convert generated private key to pkcs8! " )
) . await ;
let new_client_inter_cert = generate_inter_cert ( & priv_key , CLIENT , ( & root_cert , & root_rsa_key ) )
. await
. expect ( " Failed to generate new client intermediate cert " ) ;
client_inter_cert = new_client_inter_cert . clone ( ) ;
let client_inter_insert = certificate ::Entity ::insert ( certificate ::ActiveModel {
id : ActiveValue ::Set ( Ulid ::new ( ) . to_string ( ) ) ,
data : ActiveValue ::Set (
new_client_inter_cert . to_der ( ) . expect ( " Failed to convert cert into der! " )
) ,
key : ActiveValue ::set ( encrypted_priv_key . 1 ) ,
nonce : ActiveValue ::set ( encrypted_priv_key . 0 ) ,
cert_type : ActiveValue ::Set ( CLIENTINTER . to_string ( ) )
} )
. exec ( & connection )
. await
. expect ( " Failed to insert new client intermediate cert into database! Halting start-up. " ) ;
info! ( " Generated new client intermediate cert: {} " , client_inter_insert . last_insert_id )
}
Some ( client_inter_model ) = > {
info! ( " Found client intermediate cert: {} " , client_inter_model . id ) ;
client_inter_cert = Cert ::from_der ( & client_inter_model . data )
. expect ( " Failed to decode client intermediate cert! " ) ;
}
}
2022-09-13 09:16:28 -04:00
info! ( " Connecting to message broker... " ) ;
let amqp_addr = env ::var ( " AMQP_ADDR " )
. expect ( " AMQP_ADDR mut be set! Halting start-up. " ) ;
let amqp_connection = lapin ::Connection ::connect ( & amqp_addr , ConnectionProperties ::default ( ) )
. await
. expect ( " Failed to connect to the message broker! Halting start-up. " ) ;
let amqp_channel = amqp_connection . create_channel ( )
. await
. expect ( " Failed to create a message broker channel! Halting start-up. " ) ;
2022-09-12 02:14:52 -04:00
info! ( " Starting web server... " ) ;
let app = Router ::new ( )
2022-09-13 09:16:28 -04:00
// Users
//-- Auth
. route ( " /user/register " , post ( routes ::users ::register ::register ) )
. route ( " /user/login " , post ( routes ::users ::login ::login ) )
. route ( " /user/logout " , post ( routes ::users ::logout ::logout ) )
. route ( " /user/delete " , delete ( routes ::users ::delete ::delete ) )
//-- Information
. route ( " /user/list_sessions " , get ( routes ::users ::list_sessions ::list_sessions ) )
//-- Settings
2022-09-12 02:14:52 -04:00
// Teams
// Zones
// Records
// Proxies
2022-09-14 03:58:54 -04:00
// Admin
2022-09-12 03:55:10 -04:00
// RPC
. route ( " /rpc " , post ( rpc ::rpc ) )
// Misc
. route ( " / " , get ( routes ::status ::status ) )
2022-09-12 02:14:52 -04:00
. layer (
ServiceBuilder ::new ( )
. layer ( Extension ( connection ) )
2022-09-13 09:16:28 -04:00
. layer ( Extension ( amqp_channel ) )
2022-09-12 02:14:52 -04:00
) ;
let addr = env ::var ( " LISTEN_ADDR " )
. unwrap_or ( " 127.0.0.1:32204 " . to_string ( ) ) ;
let socket_addr : SocketAddr = addr . parse ( ) . expect ( " Failed to parse LISTEN_ADDR! Halting start-up. " ) ;
let axum_builder = axum ::Server ::try_bind ( & socket_addr ) ;
match axum_builder {
2022-09-13 09:16:28 -04:00
Ok ( axum_builder ) = > {
2022-09-12 02:14:52 -04:00
info! ( " Driptorch Controller v{} is now listening on {}! " , VERSION , socket_addr ) ;
axum_builder
. serve ( app . into_make_service_with_connect_info ::< SocketAddr > ( ) )
. await
. expect ( " Failed to bind to port! Halting start-up. " ) ;
}
Err ( _ ) = > {
error! ( " Driptorch Controller v{} failed to bind to {}! Halting start-up. " , VERSION , socket_addr ) ;
std ::process ::exit ( 1 ) ;
}
}
}