185 lines
4.7 KiB
Rust
185 lines
4.7 KiB
Rust
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")]);
|
|
let mut trainees_tmp = HashSet::from([String::from("compsoc")]);
|
|
|
|
if let Ok(x) = env::var("USERS_LIFETIME") {
|
|
for user in x.split(',').collect::<Vec<&str>>() {
|
|
users_tmp.insert(user.to_string());
|
|
}
|
|
}
|
|
|
|
if let Ok(x) = env::var("USERS_CLUBS_SOCIETIES") {
|
|
for user in x.split(',').collect::<Vec<&str>>() {
|
|
users_tmp.insert(user.to_string());
|
|
}
|
|
}
|
|
|
|
// pull from wolves csv
|
|
for user in from_csv(&db).await.unwrap_or_default() {
|
|
users_tmp.insert(user);
|
|
}
|
|
|
|
get_from_env(&mut users_tmp, &mut admins_tmp, "USERS_ADMIN");
|
|
get_from_env(&mut users_tmp, &mut committee_tmp, "USERS_COMMITTEE");
|
|
get_from_env(&mut users_tmp, &mut trainees_tmp, "USERS_TRAINEE");
|
|
|
|
// sorting makes it easier/faster
|
|
if let Ok(x) = env::var("USERS_BANNED") {
|
|
for user in x.split(',').collect::<Vec<&str>>() {
|
|
users_tmp.remove(user);
|
|
}
|
|
}
|
|
|
|
let AccountsSecure {
|
|
users,
|
|
admins,
|
|
committee,
|
|
trainees,
|
|
} = get_secure(&db, &users_tmp, &admins_tmp, &committee_tmp, &trainees_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?;
|
|
update_group(config, "skynet-trainees", &trainees, true).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn get_from_env(users: &mut HashSet<String>, other: &mut HashSet<String>, key: &str) {
|
|
if let Ok(x) = env::var(key) {
|
|
// committee automatically get added as users
|
|
for user in x.split(',').collect::<Vec<&str>>() {
|
|
other.insert(user.to_string());
|
|
users.insert(user.to_string());
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn from_csv(db: &Pool<Sqlite>) -> Result<HashSet<String>, Box<dyn Error>> {
|
|
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(id_student) = record.id_student {
|
|
if let Some(uid) = account_id_get_uid(db, &id_student).await {
|
|
uids.insert(uid);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(uids)
|
|
}
|
|
|
|
async fn account_mail_get_uid(db: &Pool<Sqlite>, mail: &str) -> Option<String> {
|
|
match sqlx::query_as::<_, Accounts>(
|
|
r#"
|
|
SELECT *
|
|
FROM accounts
|
|
WHERE mail == ?
|
|
"#,
|
|
)
|
|
.bind(mail)
|
|
.fetch_one(db)
|
|
.await
|
|
{
|
|
Ok(res) => Some(res.user.to_owned()),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
|
|
async fn account_id_get_uid(db: &Pool<Sqlite>, id: &str) -> Option<String> {
|
|
match sqlx::query_as::<_, Accounts>(
|
|
r#"
|
|
SELECT *
|
|
FROM accounts
|
|
WHERE student_id == ?
|
|
"#,
|
|
)
|
|
.bind(id)
|
|
.fetch_one(db)
|
|
.await
|
|
{
|
|
Ok(res) => Some(res.student_id.to_owned()),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
|
|
struct AccountsSecure {
|
|
users: Vec<String>,
|
|
admins: Vec<String>,
|
|
committee: Vec<String>,
|
|
trainees: Vec<String>,
|
|
}
|
|
|
|
async fn get_secure(
|
|
db: &Pool<Sqlite>, users: &HashSet<String>, admins: &HashSet<String>, committee: &HashSet<String>, trainees: &HashSet<String>,
|
|
) -> 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,
|
|
trainees: get_secure_sub(db, trainees, &mut cache).await,
|
|
}
|
|
}
|
|
|
|
async fn get_secure_sub(db: &Pool<Sqlite>, group: &HashSet<String>, cache: &mut HashSet<String>) -> Vec<String> {
|
|
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<Sqlite>, 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,
|
|
}
|
|
}
|