use ldap3::{LdapConn, Scope, SearchEntry}; use skynet_ldap_backend::{db_init, get_config, AccountWolves, Accounts, Config}; use sqlx::{Pool, Sqlite}; #[async_std::main] async fn main() -> tide::Result<()> { let config = get_config(); let db = db_init(&config).await.unwrap(); update_wolves(&config, &db).await; update_ldap(&config, &db).await; Ok(()) } async fn update_wolves(config: &Config, db: &Pool) { let mut records = vec![]; if let Ok(accounts) = get_csv(config) { for account in accounts { records.push(AccountWolves::from(account)); } } for account in records { update_account(db, &account).await; } } async fn update_ldap(config: &Config, db: &Pool) { let mut ldap = LdapConn::new(&config.ldap_host).unwrap(); ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw).unwrap().success().unwrap(); // use this to pre load a large chunk of data if let Ok(x) = ldap.search( "ou=users,dc=skynet,dc=ie", Scope::OneLevel, "(objectClass=*)", vec!["uid", "uidNumber", "skDiscord", "skMemberOf", "mail", "skID", "userPassword"], ) { if let Ok((rs, _res)) = x.success() { for entry in rs { let tmp = SearchEntry::construct(entry); let mut tmp_account = Accounts { user: "".to_string(), uid: 0, discord: None, mail: "".to_string(), student_id: "".to_string(), enabled: false, secure: false, }; // pull out the required info if tmp.attrs.contains_key("uid") && !tmp.attrs["uid"].is_empty() { tmp_account.user = tmp.attrs["uid"][0].clone(); } if tmp.attrs.contains_key("uidNumber") && !tmp.attrs["uidNumber"].is_empty() { tmp_account.uid = tmp.attrs["uidNumber"][0].clone().parse().unwrap_or(0); } if tmp.attrs.contains_key("skDiscord") && !tmp.attrs["skDiscord"].is_empty() { tmp_account.discord = Option::from(tmp.attrs["skDiscord"][0].clone()); } if tmp.attrs.contains_key("mail") && !tmp.attrs["mail"].is_empty() { tmp_account.mail = tmp.attrs["mail"][0].clone(); } if tmp.attrs.contains_key("skID") && !tmp.attrs["skID"].is_empty() { tmp_account.student_id = tmp.attrs["skID"][0].clone(); } if tmp.attrs.contains_key("skMemberOf") && !tmp.attrs["skMemberOf"].is_empty() && tmp.attrs["skMemberOf"].contains(&String::from("cn=skynet-users-linux,ou=groups,dc=skynet,dc=ie")) { tmp_account.enabled = true; } if tmp.attrs.contains_key("userPassword") && !tmp.attrs["userPassword"].is_empty() { tmp_account.secure = tmp.attrs["userPassword"][0].starts_with("{SSHA512}") } if !tmp_account.user.is_empty() { sqlx::query_as::<_, Accounts>( " INSERT OR REPLACE INTO accounts (user, uid, discord, mail, student_id, enabled, secure) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) ", ) .bind(&tmp_account.user) .bind(tmp_account.uid) .bind(&tmp_account.discord) .bind(&tmp_account.mail) .bind(&tmp_account.student_id) .bind(tmp_account.enabled) .bind(tmp_account.secure) .fetch_optional(db) .await .ok(); } } } } // done with ldap ldap.unbind().unwrap(); } #[derive(Debug, serde::Deserialize)] struct RecordCSV { #[serde(rename = "MemID")] mem_id: String, #[serde(rename = "Student Num")] id_student: String, #[serde(rename = "Contact Email")] email: String, #[serde(rename = "Expiry")] expiry: String, #[serde(rename = "First Name")] name_first: String, #[serde(rename = "Last Name")] name_second: String, } impl From for AccountWolves { fn from(input: RecordCSV) -> Self { AccountWolves { id_wolves: input.mem_id, id_student: input.id_student, email: input.email, expiry: input.expiry, name_first: input.name_first, name_second: input.name_second, } } } fn get_csv(config: &Config) -> Result, Box> { let mut records: Vec = vec![]; let csv = format!("{}/{}", &config.home, &config.csv); println!("CSV: {:?}", &csv); if let Ok(mut rdr) = csv::Reader::from_path(csv) { for result in rdr.deserialize() { // Notice that we need to provide a type hint for automatic // deserialization. let record: RecordCSV = result?; if record.mem_id.is_empty() { continue; } records.push(record); } } Ok(records) } async fn update_account(db: &Pool, account: &AccountWolves) { sqlx::query_as::<_, AccountWolves>( " INSERT OR REPLACE INTO accounts_wolves (id_wolves, id_student, email, expiry, name_first, name_second) VALUES (?1, ?2, ?3, ?4, ?5, ?6) ", ) .bind(&account.id_wolves) .bind(&account.id_student) .bind(&account.email) .bind(&account.expiry) .bind(&account.name_first) .bind(&account.name_second) .fetch_optional(db) .await .ok(); }