use crate::{ api, util::{self, get_config_profile, Result}, CONFIG_LOGIN_TEMPLATE, CONFIG_SIGNUP_TEMPLATE, }; use async_std::fs; use colored::*; use rand::distributions::{Alphanumeric, DistString}; use secd::{AuthEmail, AuthStore}; use std::{ fs::File, io::{self, stdin, stdout, Write}, str::FromStr, }; use strum::VariantNames; const DEFAULT_LOGIN_EMAIL: &str = "

You requested a login link for %secd_email_address%. Please click the following link

http://localhost:5500/myapp/iam/exchange/%secd_link%

or use code: %secd_code%

"; const DEFAULT_SIGNUP_EMAIL: &str = "

Welcome to SecD IAM

If you did not request this sign up, you can safely ignore this email. Otherwise, please click the following link to validate your account

http://localhost:5500/myapp/iam/exchange/%secd_link%

or use code: %secd_code%

"; pub async fn admin_init(is_interactive: bool) -> Result<()> { let config_dir = util::get_config_dir(); let config_profile = get_config_profile(); fs::create_dir_all(config_dir.clone()).await?; if config_profile.try_exists()? { writeln!( io::stdout(), "{} {}", config_profile.clone().display(), "already exists and there is nothing to initialize. To create a new IAM store use `iam admin create store` or modify the configuration profile directly" .yellow() )?; } else { writeln!(stdout(), "{}", "creating default profile".green())?; let mut login_template = config_dir.clone(); login_template.push(CONFIG_LOGIN_TEMPLATE); let mut f = File::create(login_template.clone())?; f.write_all(DEFAULT_LOGIN_EMAIL.as_bytes())?; let mut signup_template = config_dir.clone(); signup_template.push(CONFIG_SIGNUP_TEMPLATE); f = File::create(signup_template.clone())?; f.write_all(DEFAULT_SIGNUP_EMAIL.as_bytes())?; let mut cfg = api::Config { profile: vec![api::ConfigProfile { name: "default".to_string(), store: AuthStore::Sqlite, store_conn: format!( "sqlite://{}/{}.sql?mode=rwc", config_dir.clone().display().to_string(), Alphanumeric.sample_string(&mut rand::thread_rng(), 5), ), emailer: secd::AuthEmail::LocalStub, email_template_login: Some(login_template.display().to_string()), email_template_signup: Some(signup_template.display().to_string()), }], }; let mut input: String = String::new(); if is_interactive { writeln!(stdout(), "{}", "For a complete overview of configuration options, cancel the initialization and explore `iam help`")?; write!(stdout(), "Would you like to create a default local store with local stubs for external services?[(y)es/(n)o]: ")?; stdout().flush()?; 'outer: loop { input.clear(); stdin().read_line(&mut input)?; match input.as_str().trim() { "Y" | "y" | "Yes" | "yes" => break, "N" | "n" | "No" | "no" => { loop { write!( stdout(), "Persistence store {:?}: ", AuthStore::VARIANTS .iter() .map(|s| s.to_lowercase()) .collect::>() )?; stdout().flush()?; input.clear(); stdin().read_line(&mut input)?; match AuthStore::from_str(&input.trim()) { Ok(s) => { cfg.profile[0].store = s; break; } Err(_) => { writeln!(stdout(), "{}", "Invalid store type".red())?; } } } write!(stdout(), "Store connection string: ")?; stdout().flush()?; input.clear(); stdin().read_line(&mut input)?; cfg.profile[0].store_conn = input.trim().to_string().clone(); loop { write!( stdout(), "Email provider {:?}: ", AuthEmail::VARIANTS .iter() .map(|s| s.to_lowercase()) .collect::>() )?; stdout().flush()?; input.clear(); stdin().read_line(&mut input)?; match AuthEmail::from_str(&input.trim()) { Ok(s) => { cfg.profile[0].emailer = s; break; } Err(_) => { writeln!(stdout(), "{}", "Invalid email provider".red())?; } } } write!( stdout(), "Email template for login validation:[FilePath or Enter for default]: " )?; stdout().flush()?; input.clear(); stdin().read_line(&mut input)?; cfg.profile[0].email_template_login = Some(input.trim().to_string().clone()); write!( stdout(), "Email template for signup validation:[FilePath or Enter for default]: " )?; stdout().flush()?; input.clear(); stdin().read_line(&mut input)?; cfg.profile[0].email_template_login = Some(input.trim().to_string().clone()); break 'outer; } _ => {} } } } let mut f = File::create(config_profile.clone())?; f.write_all(toml::to_string(&cfg)?.as_bytes())?; writeln!( stdout(), "{} {} {} {} {}", "created iam config".green(), "default", "at".green(), config_dir.display().to_string(), "to hold secD iam configurations".green() )?; } Ok(()) }