added recovery key gen and finished init flow
This commit is contained in:
parent
b37867b018
commit
2264d04ded
4 changed files with 81 additions and 4 deletions
|
@ -383,6 +383,16 @@ input#ident {
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
pre.recovery-key {
|
||||
text-align: center;
|
||||
background-color: var(--clr-surface-tonal-a10);
|
||||
border: 2pt solid var(--clr-surface-tonal-a50);
|
||||
border-radius: 4pt;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
padding: .5em 2em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
header.padded>nav {
|
||||
display: flex;
|
||||
|
|
20
src/ids.rs
20
src/ids.rs
|
@ -4,12 +4,32 @@ use rocket::{form, request::FromParam};
|
|||
|
||||
use crate::db::{doll, schema::DollTagsDb};
|
||||
|
||||
const SYMBOLS: [char; 36] = [
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
];
|
||||
|
||||
/// Generate a random recovery key, of length 14 (16 with the two `-`)
|
||||
/// and format `xxxx-xxxxxx-xxxx` using the charset `a-z0-9`
|
||||
pub fn generate_recovery_key() -> String {
|
||||
let uniform = Uniform::new_inclusive::<usize, usize>(0, 35);
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let first: String = (1..=4).map(|_| SYMBOLS[uniform.sample(&mut rng)]).collect();
|
||||
let second: String = (1..=6).map(|_| SYMBOLS[uniform.sample(&mut rng)]).collect();
|
||||
let third: String = (1..=4).map(|_| SYMBOLS[uniform.sample(&mut rng)]).collect();
|
||||
|
||||
format!("{}-{}-{}", first, second, third)
|
||||
}
|
||||
|
||||
/// Generate 10 random doll tags IDs, hoping to have at least 5 of them available
|
||||
pub fn generate_ids() -> Vec<i32> {
|
||||
let uniform = Uniform::new_inclusive::<i32, i32>(100_000, 999_999);
|
||||
let mut rng = thread_rng();
|
||||
(1..=10).map(|_| uniform.sample(&mut rng)).collect()
|
||||
}
|
||||
|
||||
/// Generates 10 random doll tags IDs and check against the DB to find up to 5 free ones
|
||||
pub async fn pick_ids(mut db: DollTagsDb) -> Result<Vec<i32>, sqlx::Error> {
|
||||
let mut ids_bundle = generate_ids();
|
||||
let occupied_ids = doll::check_ids(&mut *db, &ids_bundle).await?;
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use rocket::{form::Form, http::CookieJar, response::Redirect};
|
||||
use std::net::IpAddr;
|
||||
|
||||
use rocket::{form::Form, http::CookieJar, response::Redirect, tokio::task};
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
use totp_rs::Secret;
|
||||
|
||||
use crate::{
|
||||
auth,
|
||||
auth::{self, pw},
|
||||
db::{
|
||||
self,
|
||||
otp::METHOD_TOTP,
|
||||
schema::{DollTagsDb, User},
|
||||
},
|
||||
ids::generate_recovery_key,
|
||||
pages::CommonTemplateState,
|
||||
routes::{self, error_handlers::PageResult},
|
||||
};
|
||||
|
@ -52,7 +55,8 @@ pub async fn handle_totp_enable_start(
|
|||
form: Form<OtpEnableForm>,
|
||||
user: User,
|
||||
cookies: &CookieJar<'_>,
|
||||
_meta: CommonTemplateState,
|
||||
meta: CommonTemplateState,
|
||||
client_ip: IpAddr,
|
||||
) -> PageResult {
|
||||
if db::otp::has_otp(&mut *db, &user.id, METHOD_TOTP).await? {
|
||||
return Ok(Redirect::to(uri!("/account", routes::account::settings::show_settings)).into());
|
||||
|
@ -70,5 +74,33 @@ pub async fn handle_totp_enable_start(
|
|||
))?;
|
||||
}
|
||||
|
||||
todo!("meow")
|
||||
warn!(
|
||||
"[audit|{}] [{}] enabled TOTP 2FA",
|
||||
client_ip,
|
||||
user.id.to_string(),
|
||||
);
|
||||
|
||||
let recovery_key = generate_recovery_key();
|
||||
|
||||
{
|
||||
let recovery_key = recovery_key.clone();
|
||||
let hashed_recovery_key = task::spawn_blocking(move || pw::hash(&recovery_key)).await??;
|
||||
|
||||
db::otp::add_otp_method(
|
||||
&mut *db,
|
||||
&user.id,
|
||||
&totp.get_secret_base32(),
|
||||
&hashed_recovery_key,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(Template::render(
|
||||
"account/otp/confirm",
|
||||
context! {
|
||||
meta,
|
||||
recovery_key,
|
||||
},
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
|
15
templates/account/otp/confirm.html.tera
Normal file
15
templates/account/otp/confirm.html.tera
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base" %}
|
||||
{% import "macros/form" as form %}
|
||||
{% block title %}TOTP enabled - {% endblock title %}
|
||||
{% block main %}
|
||||
<p>TOTP 2FA was successfully enabled.</p>
|
||||
|
||||
<p>
|
||||
Before moving on, it's strongly recommended that you save this key somewhere safe as it will be
|
||||
needed to disable 2FA should you lose access to your 2FA codes.
|
||||
</p>
|
||||
|
||||
<pre class="recovery-key"><code>{{recovery_key}}</code></pre>
|
||||
|
||||
<a href="/account/settings" class="btn">Finish and go to settings</a>
|
||||
{% endblock main %}
|
Loading…
Add table
Reference in a new issue