From 263a5b76e138dfab3c003d8cdc29643b17947b77 Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 6 Aug 2023 12:40:29 +0100 Subject: [PATCH 1/5] feat: switch over to having the user submit their wolves email --- Cargo.toml | 3 - src/bin/new_users.rs | 197 ------------------------------- src/methods/account_new.rs | 231 ++++++++++++++++++++++++++++++++++++- 3 files changed, 229 insertions(+), 202 deletions(-) delete mode 100644 src/bin/new_users.rs diff --git a/Cargo.toml b/Cargo.toml index 65b5ec3..e934ae3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,6 @@ name = "update_data" [[bin]] name = "update_groups" -[[bin]] -name = "new_users" - [dependencies] # for the ldap ldap3="0.11.1" diff --git a/src/bin/new_users.rs b/src/bin/new_users.rs deleted file mode 100644 index 06105ed..0000000 --- a/src/bin/new_users.rs +++ /dev/null @@ -1,197 +0,0 @@ -use lettre::{ - message::{header, MultiPart, SinglePart}, - transport::smtp::{authentication::Credentials, response::Response}, - Message, SmtpTransport, Transport, -}; -use maud::html; -use skynet_ldap_backend::{db_init, get_config, get_now_iso, get_wolves, random_string, AccountWolves, Accounts, AccountsNew, Config}; -use sqlx::{Pool, Sqlite}; - -#[async_std::main] -async fn main() { - let config = get_config(); - let db = db_init(&config).await.unwrap(); - - for record in get_wolves(&db).await { - // skynet emails not permitted - if record.email.trim().ends_with("@skynet.ie") { - continue; - } - - // check if the email is already in the db - if !check(&db, &record.email).await { - continue; - } - - // generate a auth key - let auth = random_string(50); - - match send_mail(&config, &record, &auth) { - Ok(_) => match save_to_db(&db, &record, &auth).await { - Ok(_) => {} - Err(e) => { - println!("Unable to save to db {} {e:?}", &record.email); - } - }, - Err(e) => { - println!("Unable to send mail to {} {e:?}", &record.email); - } - } - } -} - -async fn check(db: &Pool, mail: &str) -> bool { - check_pending(db, mail).await && check_users(db, mail).await -} -async fn check_users(db: &Pool, mail: &str) -> bool { - sqlx::query_as::<_, Accounts>( - r#" - SELECT * - FROM accounts - WHERE mail == ? - "#, - ) - .bind(mail) - .fetch_all(db) - .await - .unwrap_or(vec![]) - .is_empty() -} -async fn check_pending(db: &Pool, mail: &str) -> bool { - sqlx::query_as::<_, AccountsNew>( - r#" - SELECT * - FROM accounts_new - WHERE mail == ? - "#, - ) - .bind(mail) - .fetch_all(db) - .await - .unwrap_or(vec![]) - .is_empty() -} - -// using https://github.com/lettre/lettre/blob/57886c367d69b4d66300b322c94bd910b1eca364/examples/maud_html.rs -fn send_mail(config: &Config, record: &AccountWolves, auth: &str) -> Result { - let recipient = &record.name_first; - let mail = &record.email; - let url_base = "https://sso.skynet.ie"; - let link_new = format!("{url_base}/register?auth={auth}"); - let link_mod = format!("{url_base}/modify"); - let discord = "https://discord.gg/mkuKJkCuyM"; - let sender = format!("UL Computer Society <{}>", &config.mail_user); - - // Create the html we want to send. - let html = html! { - head { - title { "Hello from Skynet!" } - style type="text/css" { - "h2, h4 { font-family: Arial, Helvetica, sans-serif; }" - } - } - div style="display: flex; flex-direction: column; align-items: center;" { - h2 { "Hello from Skynet!" } - // Substitute in the name of our recipient. - p { "Hi " (recipient) "," } - p { - "As part of the UL Computer Society you get an account on our Skynet cluster." - br; - "This gives you access to some of teh various services we offer:" - ul { - li { "Email" } - li { "Gitlab" } - li { "Linux Webhost" } - } - br; - "The following invite will remain active until the end of year." - } - p { - "If you are a new member please use the following link:" - br; - a href=(link_new) { (link_new) } - } - p { - "If you are a returning user please set an email for your account at:" - br; - a href=(link_mod) { (link_mod) } - } - p { - "If you have issues please refer to our Discord server:" - br; - a href=(discord) { (discord) } - } - - p { - "Skynet Team" - br; - "UL Computer Society" - } - } - }; - - let body_text = format!( - r#" - Hi {recipient} - - As part of the UL Computer Society you get an account on our Skynet cluster. - This gives you access to some of teh various services we offer: - * Email - * Gitlab - * Linux Webhost - The following invite will remain active until the end of year. - - If you are a new member please use the following link: - {link_new} - - If you are a returning user please set an email for your account at: - {link_mod} - - If you have issues please refer to our Discord server: - {discord} - - Skynet Team - UL Computer Society - "# - ); - - // Build the message. - let email = Message::builder() - .from(sender.parse().unwrap()) - .to(mail.parse().unwrap()) - .subject("Skynet: New Account.") - .multipart( - // This is composed of two parts. - // also helps not trip spam settings (uneven number of url's - MultiPart::alternative() - .singlepart(SinglePart::builder().header(header::ContentType::TEXT_PLAIN).body(body_text)) - .singlepart(SinglePart::builder().header(header::ContentType::TEXT_HTML).body(html.into_string())), - ) - .expect("failed to build email"); - - let creds = Credentials::new(config.mail_user.clone(), config.mail_pass.clone()); - - // Open a remote connection to gmail using STARTTLS - let mailer = SmtpTransport::starttls_relay(&config.mail_smtp).unwrap().credentials(creds).build(); - - // Send the email - mailer.send(&email) -} - -async fn save_to_db(db: &Pool, record: &AccountWolves, auth: &str) -> Result, sqlx::Error> { - sqlx::query_as::<_, AccountsNew>( - " - INSERT OR REPLACE INTO accounts_new (mail, auth_code, date_iso, date_expiry, name_first, name_surname, id_student) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) - ", - ) - .bind(record.email.to_owned()) - .bind(auth.to_owned()) - .bind(get_now_iso(false)) - .bind(record.expiry.to_owned()) - .bind(record.name_first.to_owned()) - .bind(record.name_second.to_owned()) - .bind(record.id_student.to_owned()) - .fetch_optional(db) - .await -} diff --git a/src/methods/account_new.rs b/src/methods/account_new.rs index 85e26fd..df01978 100644 --- a/src/methods/account_new.rs +++ b/src/methods/account_new.rs @@ -1,5 +1,11 @@ -use crate::{get_now_iso, random_string, Accounts, AccountsNew, Config, State}; +use crate::{get_now_iso, random_string, AccountWolves, Accounts, AccountsNew, Config, State}; use ldap3::{exop::PasswordModify, LdapConn, Scope}; +use lettre::{ + message::{header, MultiPart, SinglePart}, + transport::smtp::authentication::Credentials, + Message, SmtpTransport, Transport, +}; +use maud::html; use sqlx::{Error, Pool, Sqlite}; use std::collections::HashSet; use tide::{ @@ -7,8 +13,229 @@ use tide::{ Request, }; +pub mod post { + use super::*; + + pub mod email { + use super::*; + + #[derive(Debug, Deserialize)] + struct SignupEmail { + email: String, + } + + pub async fn submit(mut req: Request) -> tide::Result { + let SignupEmail { + email, + } = req.body_json().await?; + + let config = &req.state().config; + let db = &req.state().db; + + for record in get_wolves_mail(db, &email).await { + // skynet emails not permitted + if record.email.trim().ends_with("@skynet.ie") { + continue; + } + + // check if the email is already in the db + if !check(db, &record.email).await { + continue; + } + + // generate a auth key + let auth = random_string(50); + + match send_mail(config, &record, &auth) { + Ok(_) => match save_to_db(db, &record, &auth).await { + Ok(_) => {} + Err(e) => { + println!("Unable to save to db {} {e:?}", &record.email); + } + }, + Err(e) => { + println!("Unable to send mail to {} {e:?}", &record.email); + } + } + } + + Ok(json!({"result": "success"}).into()) + } + + async fn get_wolves_mail(db: &Pool, mail: &str) -> Vec { + sqlx::query_as::<_, AccountWolves>( + r#" + SELECT * + FROM accounts_wolves + WHERE email = ? + "#, + ) + .bind(mail) + .fetch_all(db) + .await + .unwrap_or(vec![]) + } + + async fn check(db: &Pool, mail: &str) -> bool { + check_pending(db, mail).await && check_users(db, mail).await + } + async fn check_users(db: &Pool, mail: &str) -> bool { + sqlx::query_as::<_, Accounts>( + r#" + SELECT * + FROM accounts + WHERE mail == ? + "#, + ) + .bind(mail) + .fetch_all(db) + .await + .unwrap_or(vec![]) + .is_empty() + } + async fn check_pending(db: &Pool, mail: &str) -> bool { + sqlx::query_as::<_, AccountsNew>( + r#" + SELECT * + FROM accounts_new + WHERE mail == ? + "#, + ) + .bind(mail) + .fetch_all(db) + .await + .unwrap_or(vec![]) + .is_empty() + } + + // using https://github.com/lettre/lettre/blob/57886c367d69b4d66300b322c94bd910b1eca364/examples/maud_html.rs + fn send_mail(config: &Config, record: &AccountWolves, auth: &str) -> Result { + let recipient = &record.name_first; + let mail = &record.email; + let url_base = "https://sso.skynet.ie"; + let link_new = format!("{url_base}/register?auth={auth}"); + let link_mod = format!("{url_base}/modify"); + let discord = "https://discord.gg/mkuKJkCuyM"; + let sender = format!("UL Computer Society <{}>", &config.mail_user); + + // Create the html we want to send. + let html = html! { + head { + title { "Hello from Skynet!" } + style type="text/css" { + "h2, h4 { font-family: Arial, Helvetica, sans-serif; }" + } + } + div style="display: flex; flex-direction: column; align-items: center;" { + h2 { "Hello from Skynet!" } + // Substitute in the name of our recipient. + p { "Hi " (recipient) "," } + p { + "As part of the UL Computer Society you get an account on our Skynet cluster." + br; + "This gives you access to some of teh various services we offer:" + ul { + li { "Email" } + li { "Gitlab" } + li { "Linux Webhost" } + } + br; + "The following invite will remain active until the end of year." + } + p { + "If you are a new member please use the following link:" + br; + a href=(link_new) { (link_new) } + } + p { + "If you are a returning user please set an email for your account at:" + br; + a href=(link_mod) { (link_mod) } + } + p { + "If you have issues please refer to our Discord server:" + br; + a href=(discord) { (discord) } + } + + p { + "Skynet Team" + br; + "UL Computer Society" + } + } + }; + + let body_text = format!( + r#" + Hi {recipient} + + As part of the UL Computer Society you get an account on our Skynet cluster. + This gives you access to some of teh various services we offer: + * Email + * Gitlab + * Linux Webhost + The following invite will remain active until the end of year. + + If you are a new member please use the following link: + {link_new} + + If you are a returning user please set an email for your account at: + {link_mod} + + If you have issues please refer to our Discord server: + {discord} + + Skynet Team + UL Computer Society + "# + ); + + // Build the message. + let email = Message::builder() + .from(sender.parse().unwrap()) + .to(mail.parse().unwrap()) + .subject("Skynet: New Account.") + .multipart( + // This is composed of two parts. + // also helps not trip spam settings (uneven number of url's + MultiPart::alternative() + .singlepart(SinglePart::builder().header(header::ContentType::TEXT_PLAIN).body(body_text)) + .singlepart(SinglePart::builder().header(header::ContentType::TEXT_HTML).body(html.into_string())), + ) + .expect("failed to build email"); + + let creds = Credentials::new(config.mail_user.clone(), config.mail_pass.clone()); + + // Open a remote connection to gmail using STARTTLS + let mailer = SmtpTransport::starttls_relay(&config.mail_smtp).unwrap().credentials(creds).build(); + + // Send the email + mailer.send(&email) + } + + async fn save_to_db(db: &Pool, record: &AccountWolves, auth: &str) -> Result, sqlx::Error> { + sqlx::query_as::<_, AccountsNew>( + " + INSERT OR REPLACE INTO accounts_new (mail, auth_code, date_iso, date_expiry, name_first, name_surname, id_student) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) + ", + ) + .bind(record.email.to_owned()) + .bind(auth.to_owned()) + .bind(get_now_iso(false)) + .bind(record.expiry.to_owned()) + .bind(record.name_first.to_owned()) + .bind(record.name_second.to_owned()) + .bind(record.id_student.to_owned()) + .fetch_optional(db) + .await + } + } +} + #[derive(Debug, Deserialize)] -pub struct LdapNewUser { +struct LdapNewUser { auth: String, user: String, pass: String, From 158292be05e2f87ee32033ea7b592a0367ca2ab8 Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 6 Aug 2023 12:43:50 +0100 Subject: [PATCH 2/5] fix: use modules to better organise teh code --- src/main.rs | 8 +- src/methods/account_new.rs | 356 +++++++++++++++++++------------------ 2 files changed, 186 insertions(+), 178 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9cd988f..1634a36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ use skynet_ldap_backend::{ db_init, get_config, - methods::{account_new::post_new_account, account_update::post_update_ldap}, + methods::{ + account_new::post::{account, email}, + account_update::post_update_ldap, + }, State, }; @@ -21,7 +24,8 @@ async fn main() -> tide::Result<()> { let mut app = tide::with_state(state); app.at("/ldap/update").post(post_update_ldap); - app.at("/ldap/new").post(post_new_account); + app.at("/ldap/new/email").post(email::submit); + app.at("/ldap/new/account").post(account::submit); app.listen(host_port).await?; Ok(()) diff --git a/src/methods/account_new.rs b/src/methods/account_new.rs index df01978..02a31b0 100644 --- a/src/methods/account_new.rs +++ b/src/methods/account_new.rs @@ -232,223 +232,227 @@ pub mod post { .await } } -} -#[derive(Debug, Deserialize)] -struct LdapNewUser { - auth: String, - user: String, - pass: String, -} + pub mod account { + use super::*; -/// Handles initial detail entering page -/// Verify users have access to said email -/// Get users to set username and password. -pub async fn post_new_account(mut req: Request) -> tide::Result { - let LdapNewUser { - auth, - user, - pass, - } = req.body_json().await?; - - let config = &req.state().config; - let db = &req.state().db; - - // ensure there are no old requests - db_pending_clear_expired(db).await?; - - let user_db = if let Some(x) = db_get_user(db, &auth).await { - x - } else { - return Ok(json!({"result": "error", "error": "Invalid auth"}).into()); - }; - - if let Some(error) = is_valid_name(&user) { - return Ok(json!({"result": "error", "error": error}).into()); - } - - // easier to give each request its own connection - let mut ldap = LdapConn::new(&config.ldap_host)?; - - // ldap3 docs say a blank username and pass is an anon bind - ldap.simple_bind("", "")?.success()?; - - let filter_dn = format!("(uid={})", &user); - if let Ok(x) = ldap.search("ou=users,dc=skynet,dc=ie", Scope::OneLevel, &filter_dn, vec!["*"]) { - if let Ok((rs, _res)) = x.success() { - if !rs.is_empty() { - return Ok(json!({"result": "error", "error": "username not available"}).into()); - } + #[derive(Debug, Deserialize)] + struct LdapNewUser { + auth: String, + user: String, + pass: String, } - } - // done with anon ldap - ldap.unbind()?; + /// Handles initial detail entering page + /// Verify users have access to said email + /// Get users to set username and password. + pub async fn submit(mut req: Request) -> tide::Result { + let LdapNewUser { + auth, + user, + pass, + } = req.body_json().await?; - ldap_create_account(config, db, user_db, &user, &pass).await?; + let config = &req.state().config; + let db = &req.state().db; - // account now created, delete from the new table - account_verification_clear_pending(db, &auth).await?; + // ensure there are no old requests + db_pending_clear_expired(db).await?; - Ok(json!({"result": "success"}).into()) -} + let user_db = if let Some(x) = db_get_user(db, &auth).await { + x + } else { + return Ok(json!({"result": "error", "error": "Invalid auth"}).into()); + }; -// clear the db of expired ones before checking for username and validating inputs -async fn db_pending_clear_expired(pool: &Pool) -> Result, Error> { - sqlx::query_as::<_, AccountsNew>( - r#" + if let Some(error) = is_valid_name(&user) { + return Ok(json!({"result": "error", "error": error}).into()); + } + + // easier to give each request its own connection + let mut ldap = LdapConn::new(&config.ldap_host)?; + + // ldap3 docs say a blank username and pass is an anon bind + ldap.simple_bind("", "")?.success()?; + + let filter_dn = format!("(uid={})", &user); + if let Ok(x) = ldap.search("ou=users,dc=skynet,dc=ie", Scope::OneLevel, &filter_dn, vec!["*"]) { + if let Ok((rs, _res)) = x.success() { + if !rs.is_empty() { + return Ok(json!({"result": "error", "error": "username not available"}).into()); + } + } + } + + // done with anon ldap + ldap.unbind()?; + + ldap_create_account(config, db, user_db, &user, &pass).await?; + + // account now created, delete from the new table + account_verification_clear_pending(db, &auth).await?; + + Ok(json!({"result": "success"}).into()) + } + + // clear the db of expired ones before checking for username and validating inputs + async fn db_pending_clear_expired(pool: &Pool) -> Result, Error> { + sqlx::query_as::<_, AccountsNew>( + r#" DELETE FROM accounts_new WHERE date_expiry < ? "#, - ) - .bind(get_now_iso(true)) - .fetch_all(pool) - .await -} - -fn is_valid_name(name: &str) -> Option { - // max length is 31 chars - if name.len() >= 32 { - return Some(String::from("Too long, max len 31")); - } - - for (index, letter) in name.chars().enumerate() { - // no uppercase characters allowed - if letter.is_ascii_uppercase() { - return Some(String::from("Has uppercase")); + ) + .bind(get_now_iso(true)) + .fetch_all(pool) + .await } - if index == 0 { - // first character ahs to be either a letter or underscore - if !(letter.is_ascii_alphabetic() || letter == '_') { - return Some(String::from("Does not start with letter or _")); + fn is_valid_name(name: &str) -> Option { + // max length is 31 chars + if name.len() >= 32 { + return Some(String::from("Too long, max len 31")); } - } else { - // after first character options are more relaxed - if !(letter.is_ascii_alphabetic() || letter.is_ascii_digit() || letter == '_' || letter == '-') { - return Some(String::from("Contains character that is not letter, number, _ or -")); + + for (index, letter) in name.chars().enumerate() { + // no uppercase characters allowed + if letter.is_ascii_uppercase() { + return Some(String::from("Has uppercase")); + } + + if index == 0 { + // first character ahs to be either a letter or underscore + if !(letter.is_ascii_alphabetic() || letter == '_') { + return Some(String::from("Does not start with letter or _")); + } + } else { + // after first character options are more relaxed + if !(letter.is_ascii_alphabetic() || letter.is_ascii_digit() || letter == '_' || letter == '-') { + return Some(String::from("Contains character that is not letter, number, _ or -")); + } + } } + + None } - } - None -} - -async fn db_get_user(pool: &Pool, auth: &str) -> Option { - if let Ok(res) = sqlx::query_as::<_, AccountsNew>( - r#" + async fn db_get_user(pool: &Pool, auth: &str) -> Option { + if let Ok(res) = sqlx::query_as::<_, AccountsNew>( + r#" SELECT * FROM accounts_new WHERE auth_code == ? "#, - ) - .bind(auth) - .fetch_all(pool) - .await - { - if !res.is_empty() { - return Some(res[0].to_owned()); + ) + .bind(auth) + .fetch_all(pool) + .await + { + if !res.is_empty() { + return Some(res[0].to_owned()); + } + } + + None } - } - None -} + async fn ldap_create_account(config: &Config, db: &Pool, user: AccountsNew, username: &str, pass: &str) -> Result<(), ldap3::LdapError> { + let mut ldap = LdapConn::new(&config.ldap_host)?; + ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?; -async fn ldap_create_account(config: &Config, db: &Pool, user: AccountsNew, username: &str, pass: &str) -> Result<(), ldap3::LdapError> { - let mut ldap = LdapConn::new(&config.ldap_host)?; - ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?; + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", username); + let cn = format!("{} {}", &user.name_first, &user.name_surname); + let home_directory = format!("/home/{}", username); + let password_tmp = random_string(50); + let labeled_uri = format!("ldap:///ou=groups,dc=skynet,dc=ie??sub?(&(objectclass=posixgroup)(memberuid={}))", username); + let sk_mail = format!("{}@skynet.ie", username); + let sk_created = get_sk_created(); + let uid_number = get_max_uid_number(db).await; - let dn = format!("uid={},ou=users,dc=skynet,dc=ie", username); - let cn = format!("{} {}", &user.name_first, &user.name_surname); - let home_directory = format!("/home/{}", username); - let password_tmp = random_string(50); - let labeled_uri = format!("ldap:///ou=groups,dc=skynet,dc=ie??sub?(&(objectclass=posixgroup)(memberuid={}))", username); - let sk_mail = format!("{}@skynet.ie", username); - let sk_created = get_sk_created(); - let uid_number = get_max_uid_number(db).await; + // create user + ldap.add( + &dn, + vec![ + ("objectClass", HashSet::from(["top", "person", "posixaccount", "ldapPublicKey", "inetOrgPerson", "skPerson"])), + // top + ("ou", HashSet::from(["users"])), + // person + ("uid", HashSet::from([username])), + ("cn", HashSet::from([cn.as_str()])), + // posixaccount + ("uidNumber", HashSet::from([uid_number.to_string().as_str()])), + ("gidNumber", HashSet::from(["1001"])), + ("homedirectory", HashSet::from([home_directory.as_str()])), + ("userpassword", HashSet::from([password_tmp.as_str()])), + // inetOrgPerson + ("mail", HashSet::from([user.mail.as_str()])), + ("sn", HashSet::from([user.name_surname.as_str()])), + // skPerson + ("labeledURI", HashSet::from([labeled_uri.as_str()])), + ("skMail", HashSet::from([sk_mail.as_str()])), + ("skID", HashSet::from([user.id_student.as_str()])), + ("skCreated", HashSet::from([sk_created.as_str()])), + // 1 = secure, automatic since its a new account + ("skSecure", HashSet::from(["1"])), + // quotas + ("quotaEmail", HashSet::from(["10737418240"])), + ("quotaDisk", HashSet::from(["10737418240"])), + ], + )? + .success()?; - // create user - ldap.add( - &dn, - vec![ - ("objectClass", HashSet::from(["top", "person", "posixaccount", "ldapPublicKey", "inetOrgPerson", "skPerson"])), - // top - ("ou", HashSet::from(["users"])), - // person - ("uid", HashSet::from([username])), - ("cn", HashSet::from([cn.as_str()])), - // posixaccount - ("uidNumber", HashSet::from([uid_number.to_string().as_str()])), - ("gidNumber", HashSet::from(["1001"])), - ("homedirectory", HashSet::from([home_directory.as_str()])), - ("userpassword", HashSet::from([password_tmp.as_str()])), - // inetOrgPerson - ("mail", HashSet::from([user.mail.as_str()])), - ("sn", HashSet::from([user.name_surname.as_str()])), - // skPerson - ("labeledURI", HashSet::from([labeled_uri.as_str()])), - ("skMail", HashSet::from([sk_mail.as_str()])), - ("skID", HashSet::from([user.id_student.as_str()])), - ("skCreated", HashSet::from([sk_created.as_str()])), - // 1 = secure, automatic since its a new account - ("skSecure", HashSet::from(["1"])), - // quotas - ("quotaEmail", HashSet::from(["10737418240"])), - ("quotaDisk", HashSet::from(["10737418240"])), - ], - )? - .success()?; + // now to properly set teh password + let tmp = PasswordModify { + user_id: Some(&dn), + old_pass: None, + new_pass: Some(pass), + }; - // now to properly set teh password - let tmp = PasswordModify { - user_id: Some(&dn), - old_pass: None, - new_pass: Some(pass), - }; + ldap.extended(tmp).unwrap(); - ldap.extended(tmp).unwrap(); + ldap.unbind()?; - ldap.unbind()?; + Ok(()) + } - Ok(()) -} + fn get_sk_created() -> String { + use chrono::Utc; + let now = Utc::now(); -fn get_sk_created() -> String { - use chrono::Utc; - let now = Utc::now(); + format!("{}", now.format("%Y%m%d%H%M%SZ")) + } - format!("{}", now.format("%Y%m%d%H%M%SZ")) -} - -async fn get_max_uid_number(db: &Pool) -> i64 { - if let Ok(results) = sqlx::query_as::<_, Accounts>( - r#" + async fn get_max_uid_number(db: &Pool) -> i64 { + if let Ok(results) = sqlx::query_as::<_, Accounts>( + r#" SELECT * FROM accounts ORDER BY uid DESC LIMIT 1 "#, - ) - .fetch_all(db) - .await - { - if !results.is_empty() { - return results[0].uid + 1; + ) + .fetch_all(db) + .await + { + if !results.is_empty() { + return results[0].uid + 1; + } + } + + 9999 } - } - 9999 -} - -async fn account_verification_clear_pending(db: &Pool, auth_code: &str) -> Result, Error> { - sqlx::query_as::<_, AccountsNew>( - r#" + async fn account_verification_clear_pending(db: &Pool, auth_code: &str) -> Result, Error> { + sqlx::query_as::<_, AccountsNew>( + r#" DELETE FROM accounts_new WHERE auth_code == ? "#, - ) - .bind(auth_code) - .fetch_all(db) - .await + ) + .bind(auth_code) + .fetch_all(db) + .await + } + } } From a2609bd0e0ff18dc7df8384875e679c849cb8a8c Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 6 Aug 2023 12:44:41 +0100 Subject: [PATCH 3/5] fix: update teh scripts that run --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 573afe9..1631cb0 100644 --- a/flake.nix +++ b/flake.nix @@ -101,8 +101,8 @@ # modify these scripts = { - "update_data" = "*:0,15,30,45"; - "new_users" = "*:5,20,35,50"; + "update_data" = "*:0,15,30,45"; + #"new_users" = "*:5,20,35,50"; "update_groups" = "*:10"; }; From bd84c05b2ceab1015f6ca77df09be32d800738ab Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 6 Aug 2023 12:50:32 +0100 Subject: [PATCH 4/5] doc: update teh new routes for signup --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 365ea29..fff41e1 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,20 @@ Each value is either a string or ``null``. Changing ``userPassword`` requires the existing password in teh apssword field and the new one in teh value field. -### POST /ldap/new +### POST /ldap/new/email + +Kickstarts teh process of signing up to Skynet + +```json +{ + "email" : "User's wolves email" +} +``` + + +### POST /ldap/new/account + +Verifies teh user has access to this email ```json { From bce687e59772002b387f59d3c46e64cbb9d0c99f Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 6 Aug 2023 12:51:13 +0100 Subject: [PATCH 5/5] fix: increase complexity of auth code --- src/methods/account_new.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/methods/account_new.rs b/src/methods/account_new.rs index 02a31b0..0026076 100644 --- a/src/methods/account_new.rs +++ b/src/methods/account_new.rs @@ -44,7 +44,7 @@ pub mod post { } // generate a auth key - let auth = random_string(50); + let auth = random_string(75); match send_mail(config, &record, &auth) { Ok(_) => match save_to_db(db, &record, &auth).await {