use crate::{cert, client_management, schema::{self, schema}, server, user_management, config, token}; use clap::{Parser, Subcommand}; use microrm::prelude::*; #[derive(Debug, Parser)] #[clap(author, version, about, long_about = None)] struct RootArgs { #[clap(short, long, default_value_t = String::from("uauth.db"))] /// Database path db: String, #[clap(short, long, default_value_t = String::from("primary"))] /// Which realm to use, for non-server only realm: String, #[clap(subcommand)] command: Command, } #[derive(Debug, Subcommand)] enum Command { Init, Cert(CertArgs), Client(ClientArgs), Config(ConfigArgs), Group(GroupArgs), Server(ServerArgs), Token(TokenArgs), User(UserArgs), } impl RootArgs { async fn run(&self) { if let Command::Init = self.command { return self.init().await; } let storage = microrm::DB::new(schema::schema(), &self.db, microrm::CreateMode::MustExist); if let Err(e) = storage { println!("Error occured while loading database: {}", e); return; } let storage = storage.unwrap(); match &self.command { Command::Init => unreachable!(), Command::Cert(v) => v.run(&self, storage).await, Command::Config(v) => v.run(&self, storage).await, Command::Client(v) => v.run(&self, storage).await, Command::Group(v) => v.run(&self, storage).await, Command::Server(v) => v.run(&self, storage).await, Command::Token(v) => v.run(&self, storage).await, Command::User(v) => v.run(&self, storage).await, } } async fn init(&self) { // first check to see if the database is already vaguely set up let maybedb = microrm::DB::new(schema::schema(), &self.db, microrm::CreateMode::MustExist); if maybedb.is_ok() { println!("Database already initialized, not overwriting!"); return; } println!("Initializing!"); let db = microrm::DB::new( schema::schema(), &self.db, microrm::CreateMode::AllowNewDatabase, ) .expect("Unable to initialize database!"); // create primary realm db.query_interface() .add(&schema::Realm { shortname: "primary".to_string(), }) .expect("couldn't add realm"); } } #[derive(Debug, Subcommand)] enum CertCommand { Inspect, Generate, } #[derive(Debug, Parser)] struct CertArgs { #[clap(subcommand)] command: CertCommand, } impl CertArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) { match &self.command { CertCommand::Inspect => { cert::inspect(&db, &root.realm); } CertCommand::Generate => { cert::generate(&db, &root.realm); } } } } #[derive(Debug, Subcommand)] enum ClientCommand { Create { name: String }, List, Inspect { name: String }, } #[derive(Debug, Parser)] struct ClientArgs { #[clap(subcommand)] command: ClientCommand, } impl ClientArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) { match &self.command { ClientCommand::Create { name } => { client_management::create(&db, root.realm.as_str(), name); } ClientCommand::List => {} ClientCommand::Inspect { name } => { client_management::inspect(&db, name); } } } } #[derive(Debug, Subcommand)] enum ConfigCommand { Dump, Load { toml_path: String }, Set { key: String, value: String, } } #[derive(Debug, Parser)] struct ConfigArgs { #[clap(subcommand)] command: ConfigCommand, } impl ConfigArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) { match &self.command { ConfigCommand::Dump => { let qi = db.query_interface(); let config = config::Config::build_from(&qi, None); println!("config: {:?}", config); }, ConfigCommand::Set { key, value } => { todo!() }, ConfigCommand::Load { toml_path } => { let config = { let qi = db.query_interface(); config::Config::build_from(&qi, Some(toml_path)) }; { let qi = db.query_interface(); config.save(&qi); drop(config); } }, } } } #[derive(Debug, Subcommand)] enum GroupCommand {} #[derive(Debug, Parser)] struct GroupArgs { #[clap(subcommand)] command: GroupCommand, } impl GroupArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) {} } #[derive(Debug, Parser)] struct ServerArgs { #[clap(short, long)] port: Option, #[clap(short, long)] config_path: Option, } impl ServerArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) { let config = config::Config::build_from( &db.query_interface(), self.config_path.as_ref().map(|x| x.as_str()), ); server::run_server(db, config, self.port.unwrap_or(2114)).await } } #[derive(Debug, Subcommand)] enum TokenCommand { GenerateAuth { #[clap(short, long)] client: String, #[clap(short, long)] username: String, #[clap(short, long)] scopes: String }, GenerateRefresh { #[clap(short, long)] client: String, #[clap(short, long)] username: String, #[clap(short, long)] scopes: String }, Inspect { token: String }, } #[derive(Debug, Parser)] struct TokenArgs { #[clap(subcommand)] command: TokenCommand, } impl TokenArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) { let config = config::Config::build_from(&db.query_interface(), None); match &self.command { TokenCommand::GenerateAuth { client, username, scopes } => { let qi = db.query_interface(); let realm_id = qi.get().by(schema::Realm::Shortname, &root.realm).one().unwrap().expect("no such realm").id(); let token = token::generate_auth_token( &config, &qi, realm_id, qi.get().by(schema::Client::Realm, &realm_id).by(schema::Client::Shortname, client.as_str()).one().unwrap().expect("no such client").id(), qi.get().by(schema::User::Realm, &realm_id).by(schema::User::Username, username.as_str()).one().unwrap().expect("no such user").id(), scopes.split_whitespace(), ); if let Some(t) = token { println!("token: {t}"); } else { println!("Could not generate token"); } }, TokenCommand::GenerateRefresh { client, username, scopes } => { }, TokenCommand::Inspect { token } => { }, } } } #[derive(Debug, Parser)] struct CreateUserArgs { username: String, } #[derive(Debug, Parser)] struct AuthUserArgs { username: String, #[clap(short = 'p', long, parse(from_occurrences))] change_password: usize, } #[derive(Debug, Subcommand)] enum UserCommand { List, Create(CreateUserArgs), Auth(AuthUserArgs), } #[derive(Debug, Parser)] struct UserArgs { #[clap(subcommand)] command: UserCommand, } impl UserArgs { async fn run(&self, root: &RootArgs, db: microrm::DB) { match &self.command { UserCommand::List => user_management::list(&root.realm, db), UserCommand::Create(args) => { user_management::create(&root.realm, db, args.username.as_str()) } UserCommand::Auth(args) => user_management::change_auth( &root.realm, db, args.username.as_str(), args.change_password > 0, ), } } } pub fn invoked() { let args = RootArgs::parse(); smol::block_on(args.run()); // async_std::task::block_on(args.run()); }