* Refactored secret_value generation to be behind an easy to use helper
* Refactored serde facing puller functions to be more clear - Removing incorrect commentary * Changed login handler to start using mysql based api ! Further refactoring in the previous to be more readable
This commit is contained in:
parent
9d01912670
commit
5366ba9690
@ -29,7 +29,7 @@ impl Claim {
|
|||||||
.checked_add_signed(Duration::weeks(1))
|
.checked_add_signed(Duration::weeks(1))
|
||||||
.expect("Couldn't generate an expirey date")
|
.expect("Couldn't generate an expirey date")
|
||||||
.timestamp(),
|
.timestamp(),
|
||||||
cookie: generate_secret()
|
cookie: generate_cookie()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,16 +69,25 @@ fn valid_perms(member: Member, path: &str) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rng_secret(length: usize) -> String {
|
||||||
|
use getrandom::getrandom;
|
||||||
|
use base64::{encode_config, URL_SAFE};
|
||||||
|
|
||||||
|
let mut buf: Vec<u8> = vec![0;length];
|
||||||
|
getrandom(&mut buf).unwrap();
|
||||||
|
encode_config(buf,URL_SAFE)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_secret() -> String {
|
pub fn generate_secret() -> String {
|
||||||
/*
|
/*
|
||||||
* Generates a url-safe-plaintext secret for our db
|
* Generates a url-safe-plaintext secret for our db
|
||||||
* */
|
* */
|
||||||
use getrandom::getrandom;
|
return rng_secret(64);
|
||||||
use base64::{encode_config, URL_SAFE};
|
}
|
||||||
|
|
||||||
let mut buf: Vec<u8> = vec![0;64];
|
pub fn generate_cookie() -> String {
|
||||||
getrandom(&mut buf).unwrap();
|
return rng_secret(32)
|
||||||
encode_config(buf,URL_SAFE)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encrypt_secret(raw: &str) -> BcryptResult<String> {
|
pub fn encrypt_secret(raw: &str) -> BcryptResult<String> {
|
||||||
@ -86,51 +95,37 @@ pub fn encrypt_secret(raw: &str) -> BcryptResult<String> {
|
|||||||
return bcrypt::hash(raw, BCRYPT_COST);
|
return bcrypt::hash(raw, BCRYPT_COST);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_jwt_json(params: &serde_json::Value) -> Option<&str> {
|
fn jwt_from_serde(params: &serde_json::Value) -> Option<&str> {
|
||||||
// gets the `token` from the parameters
|
// gets the `token` from the parameters
|
||||||
// option<value> -> some(value) -> string
|
// option<value> -> some(value) -> string
|
||||||
return params.get("token")?.as_str();
|
return params.get("token")?.as_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn valid_jwt(token: &str) -> AuthReason {
|
async fn valid_jwt(p: &Pool, token: &str) -> AuthReason {
|
||||||
use jsonwebtoken::{
|
use jsonwebtoken::{
|
||||||
decode, DecodingKey,
|
decode, DecodingKey,
|
||||||
Validation, Algorithm
|
Validation, Algorithm
|
||||||
};
|
};
|
||||||
// TODO: add a blacklist in redis to make sure we don't ever accidently authenticate a bad
|
|
||||||
// token
|
|
||||||
// NOTE: for now we're doing purely stateless validation with a bs key
|
|
||||||
|
|
||||||
// crypto things that should prolly not fail assuming we're configured correctly
|
// crypto things that should prolly not fail assuming we're configured correctly
|
||||||
let algo = Algorithm::HS512;
|
let algo = Algorithm::HS512;
|
||||||
let dk = DecodingKey::from_base64_secret(&HMAC_SECRET).unwrap();
|
let dk = DecodingKey::from_base64_secret(&HMAC_SECRET).unwrap();
|
||||||
let raw = decode::<Claim>(token, &dk, &Validation::new(algo));
|
if let Ok(decoded) = decode::<Claim>(token, &dk, &Validation::new(algo)) {
|
||||||
|
|
||||||
// if the decoding worked then check on the redis cache for the jwt
|
// subject used for querying speed NOT security
|
||||||
// recall we have the id as a lookup but it is mapped to a session-id
|
let listed = db::auth::listed_jwt(p, decoded.claims.sub, token).await.unwrap();
|
||||||
// that mapping should be the same as the temporary usermapping
|
let active = Utc::now().timestamp() < decoded.claims.exp;
|
||||||
// Additionally: invalidating a session id is as easy as just making a new new for the user
|
|
||||||
if raw.is_err() {
|
return match listed && active {
|
||||||
|
true => AuthReason::Good,
|
||||||
|
false => AuthReason::BadKey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
return AuthReason::BadKey;
|
return AuthReason::BadKey;
|
||||||
}
|
}
|
||||||
let raw = raw.unwrap();
|
|
||||||
let id = raw.claims.sub;
|
|
||||||
let sesh_id = raw.claims.cookie;
|
|
||||||
|
|
||||||
return match db::auth::active_jwt(id, &sesh_id).await {
|
|
||||||
Ok(active) => {
|
|
||||||
match active {
|
|
||||||
true => AuthReason::Good,
|
|
||||||
false => AuthReason::BadKey
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
AuthReason::ServerIssue(format!("{}", err))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_login(params: &serde_json::Value) -> Option<(db::UBigInt, &str)> {
|
fn login_params_from_serde(params: &serde_json::Value) -> Option<(db::UBigInt, &str)> {
|
||||||
let id_v = params.get("id");
|
let id_v = params.get("id");
|
||||||
let secret_v = params.get("secret");
|
let secret_v = params.get("secret");
|
||||||
return match (id_v, secret_v) {
|
return match (id_v, secret_v) {
|
||||||
@ -153,7 +148,7 @@ pub async fn wall_entry<'path, 'pool, 'params>(
|
|||||||
|
|
||||||
// Dont need to auth if it's not required
|
// Dont need to auth if it's not required
|
||||||
let open_path = routes::is_open(path);
|
let open_path = routes::is_open(path);
|
||||||
let jwt = get_jwt_json(params);
|
let jwt = jwt_from_serde(params);
|
||||||
|
|
||||||
if open_path { // ignore the parameters since they're irelevant
|
if open_path { // ignore the parameters since they're irelevant
|
||||||
return AuthReason::OpenAuth;
|
return AuthReason::OpenAuth;
|
||||||
@ -161,9 +156,9 @@ pub async fn wall_entry<'path, 'pool, 'params>(
|
|||||||
|
|
||||||
if let Some(jwt) = jwt {
|
if let Some(jwt) = jwt {
|
||||||
// get the headers here
|
// get the headers here
|
||||||
return valid_jwt(jwt).await;
|
return valid_jwt(pool, jwt).await;
|
||||||
}
|
}
|
||||||
if let Some((id, secret)) = get_login(params) {
|
if let Some((id, secret)) = login_params_from_serde(params) {
|
||||||
// Last chance we might be hitting the /login route so we have to do the heavy auth flow
|
// Last chance we might be hitting the /login route so we have to do the heavy auth flow
|
||||||
|
|
||||||
if path != routes::AUTH_LOGIN {
|
if path != routes::AUTH_LOGIN {
|
||||||
@ -188,7 +183,7 @@ pub async fn wall_entry<'path, 'pool, 'params>(
|
|||||||
return AuthReason::NoKey;
|
return AuthReason::NoKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login_get_jwt(response: &mut hyper::Response<hyper::Body>, params: serde_json::Value) {
|
pub async fn login_get_jwt(p: &Pool, response: &mut hyper::Response<hyper::Body>, params: serde_json::Value) {
|
||||||
// basically this route generates a jwt for the user and returns via the jwt key
|
// basically this route generates a jwt for the user and returns via the jwt key
|
||||||
// in the json response
|
// in the json response
|
||||||
use jsonwebtoken::{
|
use jsonwebtoken::{
|
||||||
@ -199,24 +194,28 @@ pub async fn login_get_jwt(response: &mut hyper::Response<hyper::Body>, params:
|
|||||||
let id = params.get("id").unwrap().as_u64().unwrap(); // only route where we have the "id is there guarantee"
|
let id = params.get("id").unwrap().as_u64().unwrap(); // only route where we have the "id is there guarantee"
|
||||||
let claim = Claim::new(id);
|
let claim = Claim::new(id);
|
||||||
let header = Header::new(Algorithm::HS512);
|
let header = Header::new(Algorithm::HS512);
|
||||||
|
println!("{:?}-{:?}", header, claim);
|
||||||
let encoded = encode(
|
let encoded = encode(
|
||||||
&header,
|
&header,
|
||||||
&claim,
|
&claim,
|
||||||
&EncodingKey::from_base64_secret(HMAC_SECRET.as_ref()).expect("Couldn't encode from secret"))
|
&EncodingKey::from_base64_secret(HMAC_SECRET.as_ref()).expect("Couldn't encode from secret"))
|
||||||
.expect("Could not encode JWT");
|
.expect("Could not encode JWT");
|
||||||
|
|
||||||
if let Ok(_) = db::auth::add_jwt(id, &encoded).await {
|
match db::auth::add_jwt(p, encoded.as_ref()).await {
|
||||||
response.headers_mut().insert("Content-Type",
|
Ok(_) => {
|
||||||
|
response.headers_mut().insert("Content-Type",
|
||||||
HeaderValue::from_static("application/json"));
|
HeaderValue::from_static("application/json"));
|
||||||
|
|
||||||
let payload = serde_json::json!({
|
let payload = serde_json::json!({
|
||||||
"jwt": encoded
|
"jwt": encoded
|
||||||
});
|
});
|
||||||
*response.body_mut() = hyper::Body::from(payload.to_string());
|
*response.body_mut() = hyper::Body::from(payload.to_string());
|
||||||
}
|
},
|
||||||
else {
|
Err(e) => {
|
||||||
*response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR;
|
eprintln!("{}", e);
|
||||||
}
|
*response.status_mut() = hyper::StatusCode::INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user