use comunic_server::{cleanup_thread, server}; use comunic_server::constants::admin::{ADMIN_ROLES_LIST, AdminRole}; use comunic_server::data::admin::NewAdmin; use comunic_server::data::api_client::APIClient; use comunic_server::data::config::{conf, Config}; use comunic_server::data::error::Res; use comunic_server::data::user::UserID; use comunic_server::helpers::{account_helper, admin_account_helper, admin_roles_helper, api_helper, database}; use comunic_server::utils::date_utils::current_year; type MainActionFunction = Res; struct Action { name: &'static str, description: &'static str, arguments: Vec<&'static str>, function: Box) -> MainActionFunction>, } fn get_actions() -> Vec { vec![ // Start server Action { name: "serve", description: "Start the Comunic Server (default action)", arguments: vec![], function: Box::new(serve), }, // Show help Action { name: "help", description: "Show this help", arguments: vec![], function: Box::new(help), }, // Get the list of registered clients Action { name: "clients_list", description: "Get the list of registered clients", arguments: vec![], function: Box::new(list_clients), }, // Register a new API client Action { name: "register_client", description: "Register a new API client", arguments: vec!["name", "origin", "comment"], function: Box::new(register_client), }, // Reset a user password Action { name: "reset_password", description: "Create a password reset URL for a user", arguments: vec!["user_id"], function: Box::new(reset_password), }, // Create a new administrator Action { name: "create_admin", description: "Create a new administrator account", arguments: vec!["name", "email"], function: Box::new(create_admin), }, // Create a reset token for an admin Action { name: "create_admin_reset_token", description: "Create a new reset token to register a new access key to an admin account", arguments: vec!["email"], function: Box::new(create_admin_reset_token), }, // Get the list of available admin roles Action { name: "list_admin_roles", description: "Get the list of available admin roles", arguments: vec![], function: Box::new(list_admin_roles), }, // Attribute a role to an admin Action { name: "grant_admin_role", description: "Grant a role to an admin", arguments: vec!["mail", "role_id"], function: Box::new(grant_admin_role), }, ] } fn main() { let args: Vec = std::env::args().collect(); let conf_file = match args.get(1) { Some(el) => el.to_string(), None => { eprintln!("Please specify configuration file as first argument!"); std::process::exit(-3); } }; // Load configuration Config::load(&conf_file).expect("Could not load configuration!"); // Connect to the database database::connect(&conf().database).expect("Could not connect to database!"); // Get selected action let action = args .get(2) .map(|a| a.as_str()) .unwrap_or("serve") .to_string(); let actions = get_actions(); let selected_action = actions .iter() .filter(|p| p.name.eq(&action)) .next(); let selected_action = match selected_action { None => { eprintln!("Action {} invalid! For more information try 'help'!", action); std::process::exit(-1); } Some(a) => a }; if !selected_action.arguments.is_empty() && selected_action.arguments.len() + 3 != args.len() { eprintln!("Invalid number of arguments!"); std::process::exit(-2); } let args = match args.len() { 0 | 1 | 2 => vec![], _ => (&args[3..]).to_vec() }; let res = (selected_action.function)(args.to_vec()); res.expect("Failed to execute action!"); } /// Start Comunic Server (main action) fn serve(_a: Vec) -> Res { // Start cleanup thread cleanup_thread::start().expect("Failed to start cleanup thread!"); // Start the server Ok(server::start_server(conf())?) } fn help(_a: Vec) -> Res { println!("Comunic API v3 Server - (c) Pierre HUBERT 2012 - {}", current_year()); println!("Usage: {} [conf-file] [action] [args...]", std::env::args().next().unwrap()); println!("Available actions:"); for action in get_actions() { println!("\t{} {}\t- {}", action.name, action.arguments.iter().map(|s| format!("[{}]", s)).collect::>().join(" "), action.description ); } Ok(()) } fn list_clients(_args: Vec) -> Res { for client in api_helper::get_clients()? { println!( "Client {}\n* Name: {}\n* Domain: {}\n* Comment: {}\n* Default tokens expiration time: {}\n* Firebase project: {}\n\n", client.id, client.name, client.domain.unwrap_or("None".to_string()), client.comment.unwrap_or("None".to_string()), client.default_expiration_time, client.firebase_project_name.unwrap_or("None".to_string()) ); } Ok(()) } fn register_client(args: Vec) -> Res { let client = APIClient { id: 0, name: args[0].to_string(), domain: match args[1].is_empty() { true => None, false => Some(args[1].to_string()) }, comment: match args[2].is_empty() { true => None, false => Some(args[2].to_string()) }, default_expiration_time: 0, firebase_project_name: None, firebase_service_account_file: None, }; let id = api_helper::register_client(&client)?; println!("Registered client #{}", id); Ok(()) } fn reset_password(args: Vec) -> Res { let user_id = UserID::new(args[0].parse::()?); let token = account_helper::generate_password_reset_token(&user_id)?; println!("{}", conf().password_reset_url.replace("{TOKEN}", &token)); Ok(()) } fn create_admin(args: Vec) -> Res { let new_admin = NewAdmin { name: args[0].to_string(), email: args[1].to_string(), }; if !mailchecker::is_valid(&new_admin.email) { eprintln!("Specified email address is not valid!"); std::process::exit(-1); } let id = admin_account_helper::create(&new_admin) .expect("Failed to create account!"); println!("* New admin ID: {}", id.id()); Ok(()) } fn create_admin_reset_token(args: Vec) -> Res { let admin = admin_account_helper::find_admin_by_email(&args[0]) .expect("Failed to load admin information!"); println!("Generate a new reset token for {} ({})", admin.name, admin.email); let token = admin_account_helper::create_new_reset_token(admin.id) .expect("Failed to create admin reset token!"); println!("Reset token: {}", token.token); Ok(()) } fn list_admin_roles(_a: Vec) -> Res { println!("Here are the currently defined roles in the code:\n"); for role in Vec::from(ADMIN_ROLES_LIST) { println!("* {} - {}\n{}\n", role.id, role.name, role.description); } Ok(()) } fn grant_admin_role(args: Vec) -> Res { let role = AdminRole::from_id(&args[1]) .expect("Requested role does not exist!"); let admin = admin_account_helper::find_admin_by_email(&args[0]) .expect("Failed to load admin information!"); if admin.roles.contains(&role) { eprintln!("The administrator has already this role!"); std::process::exit(-3); } admin_roles_helper::add_role(admin.id, role)?; println!("Success."); Ok(()) }