188 lines
4.9 KiB
Rust
188 lines
4.9 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")]);
|
|
|
|
if let Ok(x) = env::var("USERS_LIFETIME") {
|
|
for user in x.split(',').collect::<Vec<&str>>() {
|
|
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::<Vec<&str>>() {
|
|
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::<Vec<&str>>() {
|
|
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::<Vec<&str>>() {
|
|
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<HashSet<String>, Box<dyn Error>> {
|
|
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<Sqlite>, mail: &str) -> Option<String> {
|
|
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<Sqlite>, id: &str) -> Option<String> {
|
|
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<String>,
|
|
admins: Vec<String>,
|
|
committee: Vec<String>,
|
|
}
|
|
|
|
async fn get_secure(db: &Pool<Sqlite>, users: &HashSet<String>, admins: &HashSet<String>, committee: &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,
|
|
}
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|