totp auth work pt2
/ build (push) Successful in 47s Details
/ build_x64 (push) Successful in 2m6s Details
/ build_arm64 (push) Successful in 2m32s Details
/ build_win64 (push) Successful in 2m35s Details

This commit is contained in:
core 2023-11-22 22:50:20 -05:00
parent 19332e519b
commit 2a5a2bb910
Signed by: core
GPG Key ID: FDBF740DADDCEECF
6 changed files with 25 additions and 9 deletions

View File

@ -1,7 +1,10 @@
CREATE TABLE totp_authenticators
(
id VARCHAR NOT NULL PRIMARY KEY,
user_id VARCHAR NOT NULL REFERENCES users(id),
secret VARCHAR NOT NULL,
verified BOOLEAN NOT NULL
id VARCHAR NOT NULL PRIMARY KEY,
user_id VARCHAR NOT NULL REFERENCES users (id) ON DELETE CASCADE,
secret VARCHAR NOT NULL,
verified BOOLEAN NOT NULL,
name VARCHAR NOT NULL,
created_at TIMESTAMP NOT NULL,
last_seen_at TIMESTAMP NOT NULL
);

View File

@ -44,6 +44,9 @@ pub struct TotpAuthenticator {
pub user_id: String,
pub secret: String,
pub verified: bool,
pub name: String,
pub created_at: SystemTime,
pub last_seen_at: SystemTime
}
#[derive(

View File

@ -8,7 +8,7 @@ use crate::response::JsonAPIResponse;
use diesel::{QueryDsl, ExpressionMethods, SelectableHelper, BelongingToDsl};
use diesel_async::RunQueryDsl;
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};
#[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 mut found_valid_code = false;
let mut chosen_auther = None;
for totp_auther in authenticators {
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 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 {
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
let new_token = AuthToken {

View File

@ -12,6 +12,7 @@ use totp_rs::{Algorithm, Secret, TOTP};
use crate::schema::totp_authenticators;
use crate::schema::users;
use crate::models::User;
use std::time::SystemTime;
#[derive(Deserialize)]
pub struct TotpAuthenticatorReq {}
@ -54,7 +55,10 @@ pub async fn create_totp_auth_req(
id: randid!(id "totp"),
user_id: session_token.user_id,
secret: secret.to_encoded().to_string(),
verified: false
verified: false,
name: "".to_string(),
created_at: SystemTime::now(),
last_seen_at: SystemTime::now()
};
handle_error!(

View File

@ -74,7 +74,7 @@ pub async fn verify_totp_req(req: Json<VerifyTotpAuthReq>, state: Data<AppState>
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

View File

@ -30,6 +30,9 @@ diesel::table! {
user_id -> Varchar,
secret -> Varchar,
verified -> Bool,
name -> Varchar,
created_at -> Timestamp,
last_seen_at -> Timestamp,
}
}