totp auth work pt2
This commit is contained in:
parent
19332e519b
commit
2a5a2bb910
|
@ -1,7 +1,10 @@
|
||||||
CREATE TABLE totp_authenticators
|
CREATE TABLE totp_authenticators
|
||||||
(
|
(
|
||||||
id VARCHAR NOT NULL PRIMARY KEY,
|
id VARCHAR NOT NULL PRIMARY KEY,
|
||||||
user_id VARCHAR NOT NULL REFERENCES users(id),
|
user_id VARCHAR NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
||||||
secret VARCHAR NOT NULL,
|
secret VARCHAR NOT NULL,
|
||||||
verified BOOLEAN NOT NULL
|
verified BOOLEAN NOT NULL,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL,
|
||||||
|
last_seen_at TIMESTAMP NOT NULL
|
||||||
);
|
);
|
|
@ -44,6 +44,9 @@ pub struct TotpAuthenticator {
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
pub secret: String,
|
pub secret: String,
|
||||||
pub verified: bool,
|
pub verified: bool,
|
||||||
|
pub name: String,
|
||||||
|
pub created_at: SystemTime,
|
||||||
|
pub last_seen_at: SystemTime
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::response::JsonAPIResponse;
|
||||||
use diesel::{QueryDsl, ExpressionMethods, SelectableHelper, BelongingToDsl};
|
use diesel::{QueryDsl, ExpressionMethods, SelectableHelper, BelongingToDsl};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use totp_rs::{Algorithm, Secret, TOTP};
|
use totp_rs::{Algorithm, Secret, TOTP};
|
||||||
use crate::schema::{auth_tokens, users};
|
use crate::schema::{auth_tokens, users, totp_authenticators};
|
||||||
use crate::models::{AuthToken, TotpAuthenticator, User};
|
use crate::models::{AuthToken, TotpAuthenticator, User};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
|
@ -42,19 +42,22 @@ pub async fn totp_req(req: Json<TotpAuthReq>, state: Data<AppState>, req_info: H
|
||||||
let authenticators: Vec<TotpAuthenticator> = handle_error!(TotpAuthenticator::belonging_to(&user).load::<TotpAuthenticator>(&mut conn).await);
|
let authenticators: Vec<TotpAuthenticator> = handle_error!(TotpAuthenticator::belonging_to(&user).load::<TotpAuthenticator>(&mut conn).await);
|
||||||
|
|
||||||
let mut found_valid_code = false;
|
let mut found_valid_code = false;
|
||||||
|
let mut chosen_auther = None;
|
||||||
|
|
||||||
for totp_auther in authenticators {
|
for totp_auther in authenticators {
|
||||||
if totp_auther.verified {
|
if totp_auther.verified {
|
||||||
let secret = Secret::Encoded(totp_auther.secret);
|
let secret = Secret::Encoded(totp_auther.secret.clone());
|
||||||
let totp_machine = handle_error!(TOTP::new(Algorithm::SHA1, 6, 1, 30, handle_error!(secret.to_bytes()), Some("Trifid".to_string()), user.email.clone()));
|
let totp_machine = handle_error!(TOTP::new(Algorithm::SHA1, 6, 1, 30, handle_error!(secret.to_bytes()), Some("Trifid".to_string()), user.email.clone()));
|
||||||
let is_valid = handle_error!(totp_machine.check_current(&req.code));
|
let is_valid = handle_error!(totp_machine.check_current(&req.code));
|
||||||
if is_valid { found_valid_code = true; break; }
|
if is_valid { found_valid_code = true; chosen_auther = Some(totp_auther); break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found_valid_code {
|
if !found_valid_code {
|
||||||
err!(StatusCode::UNAUTHORIZED, make_err!("ERR_UNAUTHORIZED", "unauthorized"));
|
err!(StatusCode::UNAUTHORIZED, make_err!("ERR_UNAUTHORIZED", "unauthorized"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle_error!(diesel::update(&(chosen_auther.unwrap())).set(totp_authenticators::dsl::last_seen_at.eq(SystemTime::now())).execute(&mut conn).await);
|
||||||
|
|
||||||
// issue auth token
|
// issue auth token
|
||||||
|
|
||||||
let new_token = AuthToken {
|
let new_token = AuthToken {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use totp_rs::{Algorithm, Secret, TOTP};
|
||||||
use crate::schema::totp_authenticators;
|
use crate::schema::totp_authenticators;
|
||||||
use crate::schema::users;
|
use crate::schema::users;
|
||||||
use crate::models::User;
|
use crate::models::User;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct TotpAuthenticatorReq {}
|
pub struct TotpAuthenticatorReq {}
|
||||||
|
@ -54,7 +55,10 @@ pub async fn create_totp_auth_req(
|
||||||
id: randid!(id "totp"),
|
id: randid!(id "totp"),
|
||||||
user_id: session_token.user_id,
|
user_id: session_token.user_id,
|
||||||
secret: secret.to_encoded().to_string(),
|
secret: secret.to_encoded().to_string(),
|
||||||
verified: false
|
verified: false,
|
||||||
|
name: "".to_string(),
|
||||||
|
created_at: SystemTime::now(),
|
||||||
|
last_seen_at: SystemTime::now()
|
||||||
};
|
};
|
||||||
|
|
||||||
handle_error!(
|
handle_error!(
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub async fn verify_totp_req(req: Json<VerifyTotpAuthReq>, state: Data<AppState>
|
||||||
err!(StatusCode::UNAUTHORIZED, make_err!("ERR_UNAUTHORIZED", "unauthorized"));
|
err!(StatusCode::UNAUTHORIZED, make_err!("ERR_UNAUTHORIZED", "unauthorized"));
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_error!(diesel::update(&authenticator).set(totp_authenticators::dsl::verified.eq(true)).execute(&mut conn).await);
|
handle_error!(diesel::update(&authenticator).set((totp_authenticators::dsl::verified.eq(true), totp_authenticators::dsl::last_seen_at.eq(SystemTime::now()))).execute(&mut conn).await);
|
||||||
|
|
||||||
// issue auth token
|
// issue auth token
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ diesel::table! {
|
||||||
user_id -> Varchar,
|
user_id -> Varchar,
|
||||||
secret -> Varchar,
|
secret -> Varchar,
|
||||||
verified -> Bool,
|
verified -> Bool,
|
||||||
|
name -> Varchar,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
last_seen_at -> Timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue