2022-03-04 08:53:49 +00:00
|
|
|
use async_std::task;
|
|
|
|
use golgi::Sbot;
|
|
|
|
use log::debug;
|
2021-12-07 12:08:21 +00:00
|
|
|
use nanorand::{Rng, WyRand};
|
2022-01-04 13:23:41 +00:00
|
|
|
use sha3::{Digest, Sha3_256};
|
2021-11-25 07:58:00 +00:00
|
|
|
|
2022-03-04 08:53:49 +00:00
|
|
|
use crate::{config_manager, error::PeachError, sbot::SbotConfig};
|
2021-08-06 17:58:40 +00:00
|
|
|
|
|
|
|
/// 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> {
|
2021-11-25 07:58:00 +00:00
|
|
|
let real_admin_password_hash = config_manager::get_admin_password_hash()?;
|
2022-01-12 11:15:04 +00:00
|
|
|
let password_hash = hash_password(password);
|
2021-11-08 15:38:10 +00:00
|
|
|
if real_admin_password_hash == password_hash {
|
2021-08-06 17:58:40 +00:00
|
|
|
Ok(())
|
|
|
|
} else {
|
2021-11-25 07:58:00 +00:00
|
|
|
Err(PeachError::PasswordIncorrect)
|
2021-08-06 17:58:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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 {
|
2021-11-25 07:58:00 +00:00
|
|
|
Err(PeachError::PasswordMismatch)
|
2021-08-06 17:58:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-10 11:21:17 +00:00
|
|
|
/// Sets a new password for the admin user
|
2021-08-06 17:58:40 +00:00
|
|
|
pub fn set_new_password(new_password: &str) -> Result<(), PeachError> {
|
2022-01-12 11:15:04 +00:00
|
|
|
let new_password_hash = hash_password(new_password);
|
2022-05-09 13:53:03 +00:00
|
|
|
config_manager::set_admin_password_hash(new_password_hash)?;
|
2021-11-25 07:58:00 +00:00
|
|
|
|
|
|
|
Ok(())
|
2021-08-06 17:58:40 +00:00
|
|
|
}
|
|
|
|
|
2021-11-08 15:38:10 +00:00
|
|
|
/// Creates a hash from a password string
|
2021-11-08 16:01:38 +00:00
|
|
|
pub fn hash_password(password: &str) -> String {
|
2022-01-04 13:23:41 +00:00
|
|
|
let mut hasher = Sha3_256::new();
|
|
|
|
// write input message
|
|
|
|
hasher.update(password);
|
|
|
|
// read hash digest
|
|
|
|
let result = hasher.finalize();
|
|
|
|
// convert `u8` to `String`
|
|
|
|
result[0].to_string()
|
2021-11-08 15:38:10 +00:00
|
|
|
}
|
|
|
|
|
2021-11-10 11:21:17 +00:00
|
|
|
/// Sets a new temporary password for the admin user
|
2021-08-06 17:58:40 +00:00
|
|
|
/// which can be used to reset the permanent password
|
|
|
|
pub fn set_new_temporary_password(new_password: &str) -> Result<(), PeachError> {
|
2022-01-12 11:15:04 +00:00
|
|
|
let new_password_hash = hash_password(new_password);
|
2022-05-09 13:53:03 +00:00
|
|
|
config_manager::set_temporary_password_hash(new_password_hash)?;
|
2021-11-25 07:58:00 +00:00
|
|
|
|
|
|
|
Ok(())
|
2021-08-06 17:58:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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> {
|
2021-11-25 07:58:00 +00:00
|
|
|
let temporary_admin_password_hash = config_manager::get_temporary_password_hash()?;
|
2022-01-12 11:15:04 +00:00
|
|
|
let password_hash = hash_password(password);
|
2021-11-08 15:38:10 +00:00
|
|
|
if temporary_admin_password_hash == password_hash {
|
2021-08-06 17:58:40 +00:00
|
|
|
Ok(())
|
|
|
|
} else {
|
2021-11-25 07:58:00 +00:00
|
|
|
Err(PeachError::PasswordIncorrect)
|
2021-08-06 17:58:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-10 11:21:17 +00:00
|
|
|
/// Generates a temporary password and sends it via ssb dm
|
2021-08-06 17:58:40 +00:00
|
|
|
/// to the ssb id configured to be the admin of the peachcloud device
|
|
|
|
pub fn send_password_reset() -> Result<(), PeachError> {
|
2021-12-07 12:08:21 +00:00
|
|
|
// initialise random number generator
|
|
|
|
let mut rng = WyRand::new();
|
|
|
|
// generate a new password of random numbers
|
|
|
|
let temporary_password = rng.generate::<u64>().to_string();
|
2021-08-06 17:58:40 +00:00
|
|
|
// save this string as a new temporary password
|
|
|
|
set_new_temporary_password(&temporary_password)?;
|
2021-11-25 07:58:00 +00:00
|
|
|
let domain = config_manager::get_peachcloud_domain()?;
|
2021-08-06 17:58:40 +00:00
|
|
|
|
|
|
|
// 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 \
|
2022-03-24 07:05:26 +00:00
|
|
|
using this link: http://peach.local/auth/reset",
|
2021-08-06 17:58:40 +00:00
|
|
|
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 \
|
2022-03-24 07:05:26 +00:00
|
|
|
using the the following link: {}/auth/reset",
|
2021-08-06 17:58:40 +00:00
|
|
|
domain
|
|
|
|
)
|
|
|
|
}
|
|
|
|
None => "".to_string(),
|
|
|
|
};
|
|
|
|
msg += &remote_link;
|
|
|
|
// finally send the message to the admins
|
2022-05-09 13:53:03 +00:00
|
|
|
let ssb_admin_ids = config_manager::get_ssb_admin_ids()?;
|
|
|
|
for ssb_admin_id in ssb_admin_ids {
|
2022-03-04 08:53:49 +00:00
|
|
|
// use golgi to send a private message on scuttlebutt
|
|
|
|
match task::block_on(publish_private_msg(&msg, &ssb_admin_id)) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => return Err(PeachError::Sbot(e)),
|
|
|
|
}
|
2021-08-06 17:58:40 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-03-04 08:53:49 +00:00
|
|
|
|
|
|
|
async fn publish_private_msg(msg: &str, recipient: &str) -> Result<(), String> {
|
|
|
|
// retrieve latest go-sbot configuration parameters
|
|
|
|
let sbot_config = SbotConfig::read().ok();
|
|
|
|
|
|
|
|
let msg = msg.to_string();
|
|
|
|
let recipient = vec![recipient.to_string()];
|
|
|
|
|
|
|
|
// initialise sbot connection with ip:port and shscap from config file
|
|
|
|
let mut sbot_client = match sbot_config {
|
|
|
|
// TODO: panics if we pass `Some(conf.shscap)` as second arg
|
|
|
|
Some(conf) => {
|
|
|
|
let ip_port = conf.lis.clone();
|
|
|
|
Sbot::init(Some(ip_port), None)
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.to_string())?
|
|
|
|
}
|
|
|
|
None => Sbot::init(None, None).await.map_err(|e| e.to_string())?,
|
|
|
|
};
|
|
|
|
|
|
|
|
debug!("Publishing a Scuttlebutt private message with temporary password");
|
|
|
|
match sbot_client.publish_private(msg, recipient).await {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(e) => Err(format!("Failed to publish private message: {}", e)),
|
|
|
|
}
|
|
|
|
}
|