mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-20 16:42:41 +00:00
Dependency updates
Updated several dependencies and switch to different totp library. - Switch oath with totp-lite oauth hasn't been updated in a long while and some dependencies could not be updated any more It now also validates a preseeding 0, as the previous library returned an int instead of a str which stripped a leading 0 - Updated rust to the current latest nightly (including build image) - Updated bootstrap css and js - Updated hadolint to latest version - Updated default rust image from v1.53 to v1.54 - Updated new nightly build/clippy messages
This commit is contained in:
parent
c666497130
commit
89b5f7c98d
14 changed files with 753 additions and 427 deletions
|
@ -62,7 +62,7 @@ fn activate_authenticator(
|
|||
let data: EnableAuthenticatorData = data.into_inner().data;
|
||||
let password_hash = data.MasterPasswordHash;
|
||||
let key = data.Key;
|
||||
let token = data.Token.into_i32()? as u64;
|
||||
let token = data.Token.into_string();
|
||||
|
||||
let mut user = headers.user;
|
||||
|
||||
|
@ -81,7 +81,7 @@ fn activate_authenticator(
|
|||
}
|
||||
|
||||
// Validate the token provided with the key, and save new twofactor
|
||||
validate_totp_code(&user.uuid, token, &key.to_uppercase(), &ip, &conn)?;
|
||||
validate_totp_code(&user.uuid, &token, &key.to_uppercase(), &ip, &conn)?;
|
||||
|
||||
_generate_recover_code(&mut user, &conn);
|
||||
|
||||
|
@ -109,16 +109,15 @@ pub fn validate_totp_code_str(
|
|||
ip: &ClientIp,
|
||||
conn: &DbConn,
|
||||
) -> EmptyResult {
|
||||
let totp_code: u64 = match totp_code.parse() {
|
||||
Ok(code) => code,
|
||||
_ => err!("TOTP code is not a number"),
|
||||
};
|
||||
if !totp_code.chars().all(char::is_numeric) {
|
||||
err!("TOTP code is not a number");
|
||||
}
|
||||
|
||||
validate_totp_code(user_uuid, totp_code, secret, ip, conn)
|
||||
}
|
||||
|
||||
pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, ip: &ClientIp, conn: &DbConn) -> EmptyResult {
|
||||
use oath::{totp_raw_custom_time, HashType};
|
||||
pub fn validate_totp_code(user_uuid: &str, totp_code: &str, secret: &str, ip: &ClientIp, conn: &DbConn) -> EmptyResult {
|
||||
use totp_lite::{totp_custom, Sha1};
|
||||
|
||||
let decoded_secret = match BASE32.decode(secret.as_bytes()) {
|
||||
Ok(s) => s,
|
||||
|
@ -130,27 +129,28 @@ pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, ip: &Cl
|
|||
_ => TwoFactor::new(user_uuid.to_string(), TwoFactorType::Authenticator, secret.to_string()),
|
||||
};
|
||||
|
||||
// Get the current system time in UNIX Epoch (UTC)
|
||||
let current_time = chrono::Utc::now();
|
||||
let current_timestamp = current_time.timestamp();
|
||||
|
||||
// The amount of steps back and forward in time
|
||||
// Also check if we need to disable time drifted TOTP codes.
|
||||
// If that is the case, we set the steps to 0 so only the current TOTP is valid.
|
||||
let steps = !CONFIG.authenticator_disable_time_drift() as i64;
|
||||
|
||||
// Get the current system time in UNIX Epoch (UTC)
|
||||
let current_time = chrono::Utc::now();
|
||||
let current_timestamp = current_time.timestamp();
|
||||
|
||||
for step in -steps..=steps {
|
||||
let time_step = current_timestamp / 30i64 + step;
|
||||
// We need to calculate the time offsite and cast it as an i128.
|
||||
// Else we can't do math with it on a default u64 variable.
|
||||
|
||||
// We need to calculate the time offsite and cast it as an u64.
|
||||
// Since we only have times into the future and the totp generator needs an u64 instead of the default i64.
|
||||
let time = (current_timestamp + step * 30i64) as u64;
|
||||
let generated = totp_raw_custom_time(&decoded_secret, 6, 0, 30, time, &HashType::SHA1);
|
||||
let generated = totp_custom::<Sha1>(30, 6, &decoded_secret, time);
|
||||
|
||||
// Check the the given code equals the generated and if the time_step is larger then the one last used.
|
||||
if generated == totp_code && time_step > twofactor.last_used as i64 {
|
||||
// If the step does not equals 0 the time is drifted either server or client side.
|
||||
if step != 0 {
|
||||
info!("TOTP Time drift detected. The step offset is {}", step);
|
||||
warn!("TOTP Time drift detected. The step offset is {}", step);
|
||||
}
|
||||
|
||||
// Save the last used time step so only totp time steps higher then this one are allowed.
|
||||
|
@ -159,7 +159,7 @@ pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, ip: &Cl
|
|||
twofactor.save(conn)?;
|
||||
return Ok(());
|
||||
} else if generated == totp_code && time_step <= twofactor.last_used as i64 {
|
||||
warn!("This or a TOTP code within {} steps back and forward has already been used!", steps);
|
||||
warn!("This TOTP or a TOTP code within {} steps back or forward has already been used!", steps);
|
||||
err!(format!("Invalid TOTP code! Server time: {} IP: {}", current_time.format("%F %T UTC"), ip.ip));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -278,7 +278,6 @@ impl<'a, 'r> FromRequest<'a, 'r> for DbConn {
|
|||
// https://docs.rs/diesel_migrations/*/diesel_migrations/macro.embed_migrations.html
|
||||
#[cfg(sqlite)]
|
||||
mod sqlite_migrations {
|
||||
#[allow(unused_imports)]
|
||||
embed_migrations!("migrations/sqlite");
|
||||
|
||||
pub fn run_migrations() -> Result<(), super::Error> {
|
||||
|
@ -315,7 +314,6 @@ mod sqlite_migrations {
|
|||
|
||||
#[cfg(mysql)]
|
||||
mod mysql_migrations {
|
||||
#[allow(unused_imports)]
|
||||
embed_migrations!("migrations/mysql");
|
||||
|
||||
pub fn run_migrations() -> Result<(), super::Error> {
|
||||
|
@ -336,7 +334,6 @@ mod mysql_migrations {
|
|||
|
||||
#[cfg(postgresql)]
|
||||
mod postgresql_migrations {
|
||||
#[allow(unused_imports)]
|
||||
embed_migrations!("migrations/postgresql");
|
||||
|
||||
pub fn run_migrations() -> Result<(), super::Error> {
|
||||
|
|
37
src/static/scripts/bootstrap-native.js
vendored
37
src/static/scripts/bootstrap-native.js
vendored
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
* Native JavaScript for Bootstrap v4.0.2 (https://thednp.github.io/bootstrap.native/)
|
||||
* Native JavaScript for Bootstrap v4.0.4 (https://thednp.github.io/bootstrap.native/)
|
||||
* Copyright 2015-2021 © dnp_theme
|
||||
* Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
|
||||
*/
|
||||
|
@ -933,14 +933,14 @@
|
|||
const self = this;
|
||||
|
||||
// initialization element
|
||||
const { element } = self;
|
||||
const { element, options } = self;
|
||||
|
||||
// set triggering elements
|
||||
self.triggers = Array.from(document.querySelectorAll(collapseToggleSelector))
|
||||
.filter((btn) => getTargetElement(btn) === element);
|
||||
|
||||
// set parent accordion
|
||||
self.parent = queryElement(self.options.parent);
|
||||
self.parent = queryElement(options.parent);
|
||||
const { parent } = self;
|
||||
|
||||
// set initial state
|
||||
|
@ -1067,6 +1067,7 @@
|
|||
const {
|
||||
element, menu, originalClass, menuEnd, options,
|
||||
} = self;
|
||||
const { offset } = options;
|
||||
const parent = element.parentElement;
|
||||
|
||||
// reset menu offset and position
|
||||
|
@ -1075,14 +1076,16 @@
|
|||
removeClass(parent, 'position-static');
|
||||
|
||||
if (!show) {
|
||||
const menuEndNow = hasClass(menu, dropdownMenuEndClass);
|
||||
parent.className = originalClass.join(' ');
|
||||
const menuAction = menuEnd && !hasClass(menu, dropdownMenuEndClass) ? addClass : removeClass;
|
||||
menuAction(menu, dropdownMenuEndClass);
|
||||
if (menuEndNow && !menuEnd) removeClass(menu, dropdownMenuEndClass);
|
||||
else if (!menuEndNow && menuEnd) addClass(menu, dropdownMenuEndClass);
|
||||
return;
|
||||
}
|
||||
|
||||
const { offset } = options;
|
||||
let positionClass = dropdownMenuClasses.find((c) => originalClass.includes(c));
|
||||
// set initial position class
|
||||
// take into account .btn-group parent as .dropdown
|
||||
let positionClass = dropdownMenuClasses.find((c) => originalClass.includes(c)) || dropdownString;
|
||||
|
||||
let dropdownMargin = {
|
||||
dropdown: [offset, 0, 0],
|
||||
|
@ -1125,8 +1128,6 @@
|
|||
// dropup
|
||||
const topExceed = targetBCR.top - menuDimensions.h < 0;
|
||||
|
||||
const btnGroup = parent.parentNode.closest('.btn-group,.btn-group-vertical');
|
||||
|
||||
// recompute position
|
||||
if (horizontalClass.includes(positionClass) && leftFullExceed && rightFullExceed) {
|
||||
positionClass = dropdownString;
|
||||
|
@ -1162,10 +1163,8 @@
|
|||
// update dropdown / dropup to handle parent btn-group element
|
||||
// as well as the dropdown-menu-end utility class
|
||||
if (verticalClass.includes(positionClass)) {
|
||||
const menuEndAction = rightExceed ? addClass : removeClass;
|
||||
|
||||
if (!btnGroup) menuEndAction(menu, dropdownMenuEndClass);
|
||||
else if (leftExceed) addClass(parent, 'position-static');
|
||||
if (!menuEnd && rightExceed) addClass(menu, dropdownMenuEndClass);
|
||||
else if (menuEnd && leftExceed) removeClass(menu, dropdownMenuEndClass);
|
||||
|
||||
if (hasClass(menu, dropdownMenuEndClass)) {
|
||||
Object.keys(dropdownPosition.menuEnd).forEach((p) => {
|
||||
|
@ -1185,6 +1184,7 @@
|
|||
document[action]('focus', dropdownDismissHandler);
|
||||
document[action]('keydown', dropdownPreventScroll);
|
||||
document[action]('keyup', dropdownKeyHandler);
|
||||
|
||||
if (self.options.display === 'dynamic') {
|
||||
window[action]('scroll', dropdownLayoutHandler, passiveHandler);
|
||||
window[action]('resize', dropdownLayoutHandler, passiveHandler);
|
||||
|
@ -1197,7 +1197,7 @@
|
|||
}
|
||||
|
||||
function getCurrentOpenDropdown() {
|
||||
const currentParent = dropdownMenuClasses
|
||||
const currentParent = dropdownMenuClasses.concat('btn-group')
|
||||
.map((c) => document.getElementsByClassName(`${c} ${showClass}`))
|
||||
.find((x) => x.length);
|
||||
|
||||
|
@ -1333,7 +1333,7 @@
|
|||
|
||||
show(related) {
|
||||
const self = this;
|
||||
const currentParent = queryElement(dropdownMenuClasses.map((c) => `.${c}.${showClass}`).join(','));
|
||||
const currentParent = queryElement(dropdownMenuClasses.concat('btn-group').map((c) => `.${c}.${showClass}`).join(','));
|
||||
const currentElement = currentParent && queryElement(dropdownSelector, currentParent);
|
||||
|
||||
if (currentElement) currentElement[dropdownComponent].hide();
|
||||
|
@ -3169,9 +3169,8 @@
|
|||
if (hideToastEvent.defaultPrevented) return;
|
||||
|
||||
clearTimeout(self.timer);
|
||||
self.timer = setTimeout(() => closeToast(self), // Bugfix by BlackDex to get autohide with a delay working.
|
||||
noTimer ? 10 : options.delay,
|
||||
);
|
||||
self.timer = setTimeout(() => closeToast(self),
|
||||
noTimer ? 10 : options.delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3484,7 +3483,7 @@
|
|||
constructor: Tooltip,
|
||||
};
|
||||
|
||||
var version = "4.0.2";
|
||||
var version = "4.0.4";
|
||||
|
||||
// import { alertInit } from '../components/alert-native.js';
|
||||
// import { buttonInit } from '../components/button-native.js';
|
||||
|
|
731
src/static/scripts/bootstrap.css
vendored
731
src/static/scripts/bootstrap.css
vendored
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue