Add rocket authentication to all routes
This commit is contained in:
@ -12,6 +12,7 @@ jsonrpc-client-core = "0.5"
|
||||
jsonrpc-client-http = "0.5"
|
||||
jsonrpc-core = "8.0.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
rust-crypto = "0.2.36"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.8"
|
||||
|
@ -4,12 +4,13 @@
|
||||
//!
|
||||
//! The configuration file is located at: "/var/lib/peachcloud/config.yml"
|
||||
|
||||
use fslock::LockFile;
|
||||
use fslock::{LockFile, IntoOsString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
|
||||
use crate::error::PeachError;
|
||||
use crate::error::*;
|
||||
use crate::password_utils::hash_password;
|
||||
|
||||
// main configuration file
|
||||
pub const YAML_PATH: &str = "/var/lib/peachcloud/config.yml";
|
||||
@ -34,6 +35,10 @@ pub struct PeachConfig {
|
||||
pub dyn_enabled: bool,
|
||||
#[serde(default)] // default is empty vector
|
||||
pub ssb_admin_ids: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub admin_password_hash: String,
|
||||
#[serde(default)]
|
||||
pub temporary_password_hash: String,
|
||||
}
|
||||
|
||||
// helper functions for serializing and deserializing PeachConfig from disc
|
||||
@ -69,6 +74,8 @@ pub fn load_peach_config() -> Result<PeachConfig, PeachError> {
|
||||
dyn_tsig_key_path: "".to_string(),
|
||||
dyn_enabled: false,
|
||||
ssb_admin_ids: Vec::new(),
|
||||
admin_password_hash: "".to_string(),
|
||||
temporary_password_hash: "".to_string(),
|
||||
};
|
||||
}
|
||||
// otherwise we load peach config from disk
|
||||
@ -141,3 +148,33 @@ pub fn delete_ssb_admin_id(ssb_id: &str) -> Result<PeachConfig, PeachError> {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_admin_password_hash(password_hash: &str) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
peach_config.admin_password_hash = password_hash.to_string();
|
||||
save_peach_config(peach_config)
|
||||
}
|
||||
|
||||
pub fn get_admin_password_hash() -> Result<String, PeachError> {
|
||||
let peach_config = load_peach_config()?;
|
||||
if !peach_config.admin_password_hash.is_empty() {
|
||||
Ok(peach_config.admin_password_hash)
|
||||
} else {
|
||||
Err(PeachError::PasswordNotSet)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_temporary_password_hash(password_hash: &str) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
peach_config.temporary_password_hash = password_hash.to_string();
|
||||
save_peach_config(peach_config)
|
||||
}
|
||||
|
||||
pub fn get_temporary_password_hash() -> Result<String, PeachError> {
|
||||
let peach_config = load_peach_config()?;
|
||||
if !peach_config.temporary_password_hash.is_empty() {
|
||||
Ok(peach_config.temporary_password_hash)
|
||||
} else {
|
||||
Err(PeachError::PasswordNotSet)
|
||||
}
|
||||
}
|
@ -63,6 +63,8 @@ pub enum PeachError {
|
||||
SaveDynDnsResultError { source: std::io::Error },
|
||||
#[snafu(display("New passwords do not match"))]
|
||||
PasswordsDoNotMatch,
|
||||
#[snafu(display("No admin password is set"))]
|
||||
PasswordNotSet,
|
||||
#[snafu(display("The supplied password was not correct"))]
|
||||
InvalidPassword,
|
||||
#[snafu(display("Error saving new password: {}", msg))]
|
||||
|
@ -1,34 +1,24 @@
|
||||
use crate::config_manager::{get_peachcloud_domain, load_peach_config};
|
||||
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;
|
||||
|
||||
/// filepath where nginx basic auth passwords are stored
|
||||
pub const HTPASSWD_FILE: &str = "/var/lib/peachcloud/passwords/htpasswd";
|
||||
/// filepath where random temporary password is stored for password resets
|
||||
pub const HTPASSWD_TEMPORARY_PASSWORD_FILE: &str =
|
||||
"/var/lib/peachcloud/passwords/temporary_password";
|
||||
/// the username of the user for nginx basic auth
|
||||
pub const PEACHCLOUD_AUTH_USER: &str = "admin";
|
||||
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 output = Command::new("/usr/bin/htpasswd")
|
||||
.arg("-vb")
|
||||
.arg(HTPASSWD_FILE)
|
||||
.arg(PEACHCLOUD_AUTH_USER)
|
||||
.arg(password)
|
||||
.output()
|
||||
.context(StdIoError {
|
||||
msg: "htpasswd is not installed",
|
||||
})?;
|
||||
if output.status.success() {
|
||||
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)
|
||||
@ -49,57 +39,46 @@ pub fn validate_new_passwords(new_password1: &str, new_password2: &str) -> Resul
|
||||
|
||||
/// Uses htpasswd to set a new password for the admin user
|
||||
pub fn set_new_password(new_password: &str) -> Result<(), PeachError> {
|
||||
let output = Command::new("/usr/bin/htpasswd")
|
||||
.arg("-cb")
|
||||
.arg(HTPASSWD_FILE)
|
||||
.arg(PEACHCLOUD_AUTH_USER)
|
||||
.arg(new_password)
|
||||
.output()
|
||||
.context(StdIoError {
|
||||
msg: "htpasswd is not installed",
|
||||
})?;
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
let err_output = String::from_utf8(output.stderr)?;
|
||||
Err(PeachError::FailedToSetNewPassword { msg: err_output })
|
||||
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 output = Command::new("/usr/bin/htpasswd")
|
||||
.arg("-cb")
|
||||
.arg(HTPASSWD_TEMPORARY_PASSWORD_FILE)
|
||||
.arg(PEACHCLOUD_AUTH_USER)
|
||||
.arg(new_password)
|
||||
.output()
|
||||
.context(StdIoError {
|
||||
msg: "htpasswd is not installed",
|
||||
})?;
|
||||
if output.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
let err_output = String::from_utf8(output.stderr)?;
|
||||
Err(PeachError::FailedToSetNewPassword { msg: err_output })
|
||||
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> {
|
||||
// TODO: confirm temporary password has not expired
|
||||
let output = Command::new("/usr/bin/htpasswd")
|
||||
.arg("-vb")
|
||||
.arg(HTPASSWD_TEMPORARY_PASSWORD_FILE)
|
||||
.arg(PEACHCLOUD_AUTH_USER)
|
||||
.arg(password)
|
||||
.output()
|
||||
.context(StdIoError {
|
||||
msg: "htpasswd is not installed",
|
||||
})?;
|
||||
if output.status.success() {
|
||||
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)
|
||||
@ -143,6 +122,7 @@ using this link: http://peach.local/reset_password",
|
||||
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)?;
|
||||
}
|
||||
|
Reference in New Issue
Block a user