
This is really just for testing purposes since the files tend to be in awkward to reach path - Removing if args.len == 0 check Basically cannon-fodder tbh * Auth now reads hmac path from environment var ! All of the above is added for the wss hmac as well + Adding command line flag [-W/--wss-hmac] to specify wss-hmac file path
187 lines
5.3 KiB
Rust
187 lines
5.3 KiB
Rust
use std::time::{SystemTime, UNIX_EPOCH};
|
|
use std::collections::HashMap;
|
|
|
|
use serde_json::json;
|
|
use mysql_async::{self, Pool};
|
|
use hyper::{Response, Body, StatusCode};
|
|
use db::{BigInt, Member, Invite};
|
|
use crate::{http, meta, qs_param};
|
|
|
|
|
|
/*
|
|
* Error handling:
|
|
* All errors raisable from this module come from mysql_async and thus
|
|
* are of the enum mysql_async::error::Error
|
|
*/
|
|
|
|
async fn valid_invite(pool: &Pool, id: BigInt) -> bool {
|
|
/*
|
|
* Fetches an invite from the database to check for validity
|
|
*/
|
|
let query = if let Ok(inv) = Invite::get(pool, id).await {
|
|
match inv {
|
|
db::Response::Row(data) => Some(data),
|
|
_ => None
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(invite) = query {
|
|
// if expires at all
|
|
if invite.expires {
|
|
let now: i64 = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.expect("Systemtime fetch failed")
|
|
.as_millis() as i64;
|
|
|
|
// old?
|
|
let mut valid_status = now < invite.id;
|
|
// used?
|
|
if invite.uses.is_some() && valid_status == false {
|
|
valid_status = invite.uses.unwrap() <= 0; // safe unwrap since we know its Some(_)
|
|
}
|
|
return valid_status
|
|
}
|
|
// no expiry date? no problem
|
|
return true
|
|
}
|
|
|
|
// prolly not a real id
|
|
return false
|
|
|
|
}
|
|
|
|
async fn use_invite(pool: &Pool, code: Option<BigInt>) -> Option<Member>{
|
|
/*
|
|
* Attempts to change the state of the current invite being provided
|
|
*/
|
|
use crate::auth;
|
|
use crate::perms::GENERAL_NEW;
|
|
let id = match code {
|
|
Some(id) => id,
|
|
None => 0
|
|
};
|
|
|
|
// some random comment
|
|
if valid_invite(pool, id).await {
|
|
let raw_secret = auth::generate_secret();
|
|
let secret = auth::encrypt_secret(&raw_secret).unwrap();
|
|
return match Member::add(pool, "Anonymous".into(), &secret, GENERAL_NEW).await {
|
|
Ok(dbresponse) => {
|
|
match dbresponse {
|
|
db::Response::Row(mut member) => {
|
|
member.secret = raw_secret;
|
|
Some(member)
|
|
}
|
|
_ => None
|
|
}
|
|
},
|
|
// TODO: logggin or something idk
|
|
Err(_) => None
|
|
}
|
|
}
|
|
// The invite itself was not valid
|
|
// Returning None because we couldn't actually create a proper secret to store
|
|
return None;
|
|
}
|
|
|
|
pub async fn join(pool: &Pool, response: &mut Response<Body>, params: HashMap<String, String>) {
|
|
/*
|
|
* Main dispatcher for dealing with an attempted join via a given invide code
|
|
*
|
|
*/
|
|
let code = match params.get("code") {
|
|
Some(val) => {
|
|
// i64 because we're using unix timestamps and basically the database is dumb
|
|
if let Ok(num) = (*val).to_string().parse::<i64>() {
|
|
Some(num)
|
|
} else {
|
|
None
|
|
}
|
|
|
|
},
|
|
None => None
|
|
};
|
|
|
|
// Returns a new member if the code is used successfully
|
|
match use_invite(&pool, code).await {
|
|
Some(new_account) => {
|
|
http::set_json_body(response, json!({
|
|
"user": new_account,
|
|
"server": meta::get_config()
|
|
}))
|
|
},
|
|
None => {
|
|
*response.status_mut() = StatusCode::NOT_FOUND;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async fn allowed_perm_invite(pool: &Pool, uid: u64) -> bool {
|
|
use crate::perms;
|
|
|
|
return match Member::get(pool, uid).await {
|
|
Ok(response) => match response {
|
|
db::Response::Row(user) => perms::has_perm(user.permissions, perms::CREATE_PERM_INVITES),
|
|
_ => false
|
|
},
|
|
Err(e) => {
|
|
eprintln!("[HTTP-DB-ERROR] {}", e);
|
|
false
|
|
}
|
|
};
|
|
}
|
|
pub async fn create(pool: &Pool, response: &mut Response<Body>, params: HashMap<String, String>) {
|
|
/*
|
|
* Creates a new invite
|
|
* Parameters required asked of the user to provide
|
|
* uses : Option<i64>
|
|
* expires: Option<bool>
|
|
*/
|
|
|
|
let id = qs_param!(params, "id", u64).unwrap();
|
|
|
|
let use_count = match params.get("uses") {
|
|
Some(val) => {
|
|
match (*val).to_string().parse::<i64>() {
|
|
Ok(count) => Some(count),
|
|
Err(_) => None
|
|
}
|
|
},
|
|
None => None
|
|
};
|
|
|
|
let expirey_request = match params.get("expires") {
|
|
Some(exp_val) => {
|
|
match exp_val.to_string().parse::<bool>() {
|
|
Ok(exp) => {
|
|
match exp {
|
|
true => allowed_perm_invite(pool, id).await,
|
|
false => false
|
|
}
|
|
},
|
|
_ => false
|
|
}
|
|
}
|
|
None => true
|
|
};
|
|
|
|
// TODO: prolly add some kind option to set an expire time
|
|
let invite = Invite::new(use_count, expirey_request);
|
|
|
|
match invite.add(pool).await {
|
|
Ok(_) => {
|
|
// return the id of the invite
|
|
// Link format from here is basically hostname.io:4536/join?code=<some-code>
|
|
http::set_json_body(response, serde_json::json!({"invite":invite}))
|
|
},
|
|
Err(mysqle) => {
|
|
println!("\tINVITES::CREATE::ERROR: {}", mysqle);
|
|
*response.status_mut() = StatusCode::BAD_REQUEST;
|
|
}
|
|
}
|
|
}
|