use skynet_ldap_backend::{db_init, get_config, get_now_iso, get_wolves, update_group, Accounts, Config}; use sqlx::{Pool, Sqlite}; use std::{collections::HashSet, env, error::Error}; #[async_std::main] async fn main() -> tide::Result<()> { let config = get_config(); update(&config).await?; Ok(()) } async fn update(config: &Config) -> tide::Result<()> { let db = db_init(config).await.unwrap(); // default user to ensure group is never empty let mut users_tmp = HashSet::from([String::from("compsoc")]); let mut admins_tmp = HashSet::from([String::from("compsoc")]); let mut committee_tmp = HashSet::from([String::from("compsoc")]); if let Ok(x) = env::var("USERS_LIFETIME") { for user in x.split(',').collect::>() { users_tmp.insert(user.to_string()); } } // pull from wolves csv for user in from_csv(config).await.unwrap_or_default() { users_tmp.insert(user); } if let Ok(x) = env::var("USERS_ADMIN") { // admins automatically get added as users for user in x.split(',').collect::>() { admins_tmp.insert(user.to_string()); users_tmp.insert(user.to_string()); } } // read from teh env if let Ok(x) = env::var("USERS_COMMITTEE") { // committee automatically get added as users for user in x.split(',').collect::>() { committee_tmp.insert(user.to_string()); users_tmp.insert(user.to_string()); } } // sorting makes it easier/faster if let Ok(x) = env::var("USERS_BANNED") { for user in x.split(',').collect::>() { users_tmp.remove(user); } } let AccountsSecure { users, admins, committee, } = get_secure(&db, &users_tmp, &admins_tmp, &committee_tmp).await; update_group(config, "skynet-users", &users, true).await?; update_group(config, "skynet-admins", &admins, true).await?; update_group(config, "skynet-committee", &committee, true).await?; Ok(()) } async fn from_csv(config: &Config) -> Result, Box> { let db = db_init(config).await.unwrap(); let mut uids = HashSet::new(); for record in get_wolves(&db).await { // only import users if it is actually active. if record.expiry < get_now_iso(true) { continue; } if let Some(uid) = account_mail_get_uid(&db, &record.email).await { uids.insert(uid); } else if let Some(uid) = account_id_get_uid(&db, &record.id_student).await { uids.insert(uid); } } Ok(uids) } async fn account_mail_get_uid(db: &Pool, mail: &str) -> Option { match sqlx::query_as::<_, Accounts>( r#" SELECT user FROM accounts WHERE mail == ? "#, ) .bind(mail) .fetch_all(db) .await { Ok(res) => { if res.is_empty() { None } else { Some(res[0].user.to_owned()) } } Err(_) => None, } } async fn account_id_get_uid(db: &Pool, id: &str) -> Option { match sqlx::query_as::<_, Accounts>( r#" SELECT user FROM accounts WHERE student_id == ? "#, ) .bind(id) .fetch_all(db) .await { Ok(res) => { if res.is_empty() { None } else { Some(res[0].student_id.to_owned()) } } Err(_) => None, } } struct AccountsSecure { users: Vec, admins: Vec, committee: Vec, } async fn get_secure(db: &Pool, users: &HashSet, admins: &HashSet, committee: &HashSet) -> AccountsSecure { // to avoid searching for teh same thing again. let mut cache = HashSet::new(); AccountsSecure { users: get_secure_sub(db, users, &mut cache).await, admins: get_secure_sub(db, admins, &mut cache).await, committee: get_secure_sub(db, committee, &mut cache).await, } } async fn get_secure_sub(db: &Pool, group: &HashSet, cache: &mut HashSet) -> Vec { let mut tmp = vec![]; for user in group { // check the cache first let mut add = false; if cache.get(user).is_some() { add = true; } else if is_secure(db, user).await { cache.insert(user.to_string()); add = true; } if add { tmp.push(user.clone()); } } tmp } async fn is_secure(db: &Pool, user: &str) -> bool { match sqlx::query_as::<_, Accounts>( r#" SELECT * FROM accounts WHERE user == ? AND secure == 1 "#, ) .bind(user) .fetch_all(db) .await { Ok(res) => !res.is_empty(), Err(_) => false, } }