131 lines
4.6 KiB
Rust
131 lines
4.6 KiB
Rust
use crate::config_manager::{get_peachcloud_domain, load_peach_config,
|
|
set_admin_password_hash, get_admin_password_hash,
|
|
get_temporary_password_hash, set_temporary_password_hash};
|
|
use crate::error::PeachError;
|
|
use crate::error::StdIoError;
|
|
use crate::sbot_client;
|
|
use log::info;
|
|
use rand::distributions::Alphanumeric;
|
|
use rand::{thread_rng, Rng};
|
|
use snafu::ResultExt;
|
|
use std::iter;
|
|
use std::process::Command;
|
|
use crypto::digest::Digest;
|
|
use crypto::sha3::Sha3;
|
|
|
|
/// Returns Ok(()) if the supplied password is correct,
|
|
/// and returns Err if the supplied password is incorrect.
|
|
pub fn verify_password(password: &str) -> Result<(), PeachError> {
|
|
let real_admin_password_hash = get_admin_password_hash()?;
|
|
let password_hash = hash_password(&password.to_string());
|
|
if real_admin_password_hash == password_hash {
|
|
Ok(())
|
|
} else {
|
|
Err(PeachError::InvalidPassword)
|
|
}
|
|
}
|
|
|
|
/// Checks if the given passwords are valid, and returns Ok() if they are and
|
|
/// a PeachError otherwise.
|
|
/// Currently this just checks that the passwords are the same,
|
|
/// but could be extended to test if they are strong enough.
|
|
pub fn validate_new_passwords(new_password1: &str, new_password2: &str) -> Result<(), PeachError> {
|
|
if new_password1 == new_password2 {
|
|
Ok(())
|
|
} else {
|
|
Err(PeachError::PasswordsDoNotMatch)
|
|
}
|
|
}
|
|
|
|
/// Uses htpasswd to set a new password for the admin user
|
|
pub fn set_new_password(new_password: &str) -> Result<(), PeachError> {
|
|
let new_password_hash = hash_password(&new_password.to_string());
|
|
let result = set_admin_password_hash(&new_password_hash);
|
|
match result {
|
|
Ok(_) => {
|
|
Ok(())
|
|
},
|
|
Err(err) => {
|
|
Err(PeachError::FailedToSetNewPassword { msg: "failed to save password hash".to_string() })
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Creates a hash from a password string
|
|
pub fn hash_password(password: &String) -> String {
|
|
let mut hasher = Sha3::sha3_256();
|
|
hasher.input_str(password);
|
|
hasher.result_str()
|
|
}
|
|
|
|
/// Uses htpasswd to set a new temporary password for the admin user
|
|
/// which can be used to reset the permanent password
|
|
pub fn set_new_temporary_password(new_password: &str) -> Result<(), PeachError> {
|
|
let new_password_hash = hash_password(&new_password.to_string());
|
|
let result = set_temporary_password_hash(&new_password_hash);
|
|
match result {
|
|
Ok(_) => {
|
|
Ok(())
|
|
},
|
|
Err(err) => {
|
|
Err(PeachError::FailedToSetNewPassword { msg: "failed to save temporary password hash".to_string() })
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns Ok(()) if the supplied temp_password is correct,
|
|
/// and returns Err if the supplied temp_password is incorrect
|
|
pub fn verify_temporary_password(password: &str) -> Result<(), PeachError> {
|
|
let temporary_admin_password_hash = get_temporary_password_hash()?;
|
|
let password_hash = hash_password(&password.to_string());
|
|
if temporary_admin_password_hash == password_hash {
|
|
Ok(())
|
|
} else {
|
|
Err(PeachError::InvalidPassword)
|
|
}
|
|
}
|
|
|
|
/// generates a temporary password and sends it via ssb dm
|
|
/// to the ssb id configured to be the admin of the peachcloud device
|
|
pub fn send_password_reset() -> Result<(), PeachError> {
|
|
// first generate a new random password of ascii characters
|
|
let mut rng = thread_rng();
|
|
let temporary_password: String = iter::repeat(())
|
|
.map(|()| rng.sample(Alphanumeric))
|
|
.map(char::from)
|
|
.take(10)
|
|
.collect();
|
|
// save this string as a new temporary password
|
|
set_new_temporary_password(&temporary_password)?;
|
|
let domain = get_peachcloud_domain()?;
|
|
|
|
// then send temporary password as a private ssb message to admin
|
|
let mut msg = format!(
|
|
"Your new temporary password is: {}
|
|
|
|
If you are on the same WiFi network as your PeachCloud device you can reset your password \
|
|
using this link: http://peach.local/reset_password",
|
|
temporary_password
|
|
);
|
|
// if there is an external domain, then include remote link in message
|
|
// otherwise dont include it
|
|
let remote_link = match domain {
|
|
Some(domain) => {
|
|
format!(
|
|
"\n\nOr if you are on a different WiFi network, you can reset your password \
|
|
using the the following link: {}/reset_password",
|
|
domain
|
|
)
|
|
}
|
|
None => "".to_string(),
|
|
};
|
|
msg += &remote_link;
|
|
// finally send the message to the admins
|
|
let peach_config = load_peach_config()?;
|
|
info!("sending password reset: {}", msg);
|
|
for ssb_admin_id in peach_config.ssb_admin_ids {
|
|
sbot_client::private_message(&msg, &ssb_admin_id)?;
|
|
}
|
|
Ok(())
|
|
}
|