124 lines
3.8 KiB
Rust
124 lines
3.8 KiB
Rust
use std::ops::Deref;
|
|
|
|
use actix_web::{HttpResponse, Responder};
|
|
use askama::Template;
|
|
use base64::Engine as _;
|
|
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
|
use qrcode_generator::QrCodeEcc;
|
|
|
|
use crate::constants::MAX_SECOND_FACTOR_NAME_LEN;
|
|
use crate::controllers::settings_controller::BaseSettingsPage;
|
|
use crate::data::app_config::AppConfig;
|
|
use crate::data::critical_route::CriticalRoute;
|
|
use crate::data::current_user::CurrentUser;
|
|
use crate::data::totp_key::TotpKey;
|
|
use crate::data::user::User;
|
|
use crate::data::webauthn_manager::WebAuthManagerReq;
|
|
use crate::utils::time::fmt_time;
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "settings/two_factors_page.html")]
|
|
struct TwoFactorsPage<'a> {
|
|
p: BaseSettingsPage<'a>,
|
|
user: &'a User,
|
|
last_2fa_auth: Option<String>,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "settings/add_2fa_totp_page.html")]
|
|
struct AddTotpPage<'a> {
|
|
p: BaseSettingsPage<'a>,
|
|
qr_code: String,
|
|
account_name: String,
|
|
secret_key: String,
|
|
max_name_len: usize,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "settings/add_webauthn_page.html")]
|
|
struct AddWebauhtnPage<'a> {
|
|
p: BaseSettingsPage<'a>,
|
|
opaque_state: String,
|
|
challenge_json: String,
|
|
max_name_len: usize,
|
|
}
|
|
|
|
/// Manage two factors authentication methods route
|
|
pub async fn two_factors_route(_critical: CriticalRoute, user: CurrentUser) -> impl Responder {
|
|
HttpResponse::Ok().body(
|
|
TwoFactorsPage {
|
|
p: BaseSettingsPage::get("Two factor auth", &user, None, None),
|
|
user: user.deref(),
|
|
last_2fa_auth: user.last_2fa_auth.map(fmt_time),
|
|
}
|
|
.render()
|
|
.unwrap(),
|
|
)
|
|
}
|
|
|
|
/// Configure a new TOTP authentication factor
|
|
pub async fn add_totp_factor_route(_critical: CriticalRoute, user: CurrentUser) -> impl Responder {
|
|
let key = TotpKey::new_random();
|
|
|
|
let qr_code = qrcode_generator::to_png_to_vec(
|
|
key.url_for_user(&user, AppConfig::get()),
|
|
QrCodeEcc::Low,
|
|
1024,
|
|
);
|
|
let qr_code = match qr_code {
|
|
Ok(q) => q,
|
|
Err(e) => {
|
|
log::error!("Failed to generate QrCode! {:?}", e);
|
|
return HttpResponse::InternalServerError().body("Failed to generate QrCode!");
|
|
}
|
|
};
|
|
|
|
HttpResponse::Ok().body(
|
|
AddTotpPage {
|
|
p: BaseSettingsPage::get("New authenticator app", &user, None, None),
|
|
qr_code: BASE64_STANDARD.encode(qr_code),
|
|
account_name: key.account_name(&user, AppConfig::get()),
|
|
secret_key: key.get_secret(),
|
|
max_name_len: MAX_SECOND_FACTOR_NAME_LEN,
|
|
}
|
|
.render()
|
|
.unwrap(),
|
|
)
|
|
}
|
|
|
|
/// Configure a new security key factor
|
|
pub async fn add_webauthn_factor_route(
|
|
_critical: CriticalRoute,
|
|
user: CurrentUser,
|
|
manager: WebAuthManagerReq,
|
|
) -> impl Responder {
|
|
let registration_request = match manager.start_register(&user) {
|
|
Ok(r) => r,
|
|
Err(e) => {
|
|
log::error!("Failed to request new key! {:?}", e);
|
|
return HttpResponse::InternalServerError()
|
|
.body("Failed to generate request for registration!");
|
|
}
|
|
};
|
|
|
|
let challenge_json = match serde_json::to_string(®istration_request.creation_challenge) {
|
|
Ok(r) => r,
|
|
Err(e) => {
|
|
log::error!("Failed to serialize challenge! {:?}", e);
|
|
return HttpResponse::InternalServerError().body("Failed to serialize challenge!");
|
|
}
|
|
};
|
|
|
|
HttpResponse::Ok().body(
|
|
AddWebauhtnPage {
|
|
p: BaseSettingsPage::get("New security key", &user, None, None),
|
|
|
|
opaque_state: registration_request.opaque_state,
|
|
challenge_json: urlencoding::encode(&challenge_json).to_string(),
|
|
max_name_len: MAX_SECOND_FACTOR_NAME_LEN,
|
|
}
|
|
.render()
|
|
.unwrap(),
|
|
)
|
|
}
|