Update config_manager to check from three sources of configuration #105
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2430,6 +2430,7 @@ dependencies = [
|
||||
"jsonrpc-client-core",
|
||||
"jsonrpc-client-http",
|
||||
"jsonrpc-core 8.0.1",
|
||||
"lazy_static",
|
||||
"log 0.4.16",
|
||||
"nanorand",
|
||||
"regex",
|
||||
|
||||
@ -21,3 +21,4 @@ serde_json = "1.0"
|
||||
serde_yaml = "0.8"
|
||||
toml = "0.5"
|
||||
sha3 = "0.10"
|
||||
lazy_static = "1.4.0"
|
||||
|
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
objcopy = { path ="aarch64-linux-gnu-objcopy" }
|
||||
strip = { path ="aarch64-linux-gnu-strip" }
|
||||
@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "debug"
|
||||
version = "0.1.0"
|
||||
authors = ["notplants <mfowler.email@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
peach-lib = { path = "../" }
|
||||
env_logger = "0.6"
|
||||
chrono = "0.4.19"
|
||||
@ -1,65 +0,0 @@
|
||||
use peach_lib::dyndns_client::{dyndns_update_ip, register_domain, is_dns_updater_online, log_successful_nsupdate, get_num_seconds_since_successful_dns_update };
|
||||
use peach_lib::password_utils::{verify_password, set_new_password, verify_temporary_password, set_new_temporary_password, send_password_reset};
|
||||
use peach_lib::config_manager::{add_ssb_admin_id, delete_ssb_admin_id};
|
||||
use peach_lib::sbot_client;
|
||||
use std::process;
|
||||
use chrono::prelude::*;
|
||||
|
||||
|
||||
fn main() {
|
||||
// initalize the logger
|
||||
env_logger::init();
|
||||
//
|
||||
// println!("Hello, world its debug!");
|
||||
// let result = set_new_password("password3");
|
||||
// println!("result: {:?}", result);
|
||||
//
|
||||
// let result = verify_password("password1");
|
||||
// println!("result should be error: {:?}", result);
|
||||
//
|
||||
// let result = verify_password("password3");
|
||||
// println!("result should be ok: {:?}", result);
|
||||
//
|
||||
//
|
||||
// println!("Testing temporary passwords");
|
||||
// let result = set_new_temporary_password("abcd");
|
||||
// println!("result: {:?}", result);
|
||||
//
|
||||
// let result = verify_temporary_password("password1");
|
||||
// println!("result should be error: {:?}", result);
|
||||
//
|
||||
// let result = verify_temporary_password("abcd");
|
||||
// println!("result should be ok: {:?}", result);
|
||||
//
|
||||
let result = send_password_reset();
|
||||
println!("send password reset result should be ok: {:?}", result);
|
||||
|
||||
// sbot_client::post("hi cat");
|
||||
// let result = sbot_client::whoami();
|
||||
// let result = sbot_client::create_invite(50);
|
||||
// let result = sbot_client::post("is this working");
|
||||
// println!("result: {:?}", result);
|
||||
// let result = sbot_client::post("nice we have contact");
|
||||
// let result = sbot_client::update_pub_name("vermont-pub");
|
||||
// let result = sbot_client::private_message("this is a private message", "@LZx+HP6/fcjUm7vef2eaBKAQ9gAKfzmrMVGzzdJiQtA=.ed25519");
|
||||
// println!("result: {:?}", result);
|
||||
|
||||
// let result = send_password_reset();
|
||||
// let result = add_ssb_admin_id("xyzdab");
|
||||
// println!("result: {:?}", result);
|
||||
// let result = delete_ssb_admin_id("xyzdab");
|
||||
// println!("result: {:?}", result);
|
||||
// let result = delete_ssb_admin_id("ab");
|
||||
// println!("result: {:?}", result);
|
||||
|
||||
//// let result = log_successful_nsupdate();
|
||||
//// let result = get_num_seconds_since_successful_dns_update();
|
||||
// let is_online = is_dns_updater_online();
|
||||
// println!("is online: {:?}", is_online);
|
||||
//
|
||||
//// let result = get_last_successful_dns_update();
|
||||
//// println!("result: {:?}", result);
|
||||
//// register_domain("newquarter299.dyn.peachcloud.org");
|
||||
// let result = dyndns_update_ip();
|
||||
// println!("result: {:?}", result);
|
||||
}
|
||||
11
peach-lib/examples/config.rs
Normal file
11
peach-lib/examples/config.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use peach_lib::config_manager::{get_config_value, save_config_value};
|
||||
|
glyph
commented
It's a neat pattern to include a code usage pattern as an example like this. It's a neat pattern to include a code usage pattern as an example like this.
notplants
commented
yes I think so too! I originally made this file just out of convenience of needing a way to test my code, but then thought it was kind of a neat pattern to keep little code examples around here. yes I think so too!
I originally made this file just out of convenience of needing a way to test my code, but then thought it was kind of a neat pattern to keep little code examples around here.
|
||||
|
||||
fn main() {
|
||||
println!("Running example of PeachCloud configuration management");
|
||||
let v = get_config_value("ADDR").unwrap();
|
||||
println!("ADDR: {}", v);
|
||||
|
||||
save_config_value("ADDR", "1.1.1.1");
|
||||
let v = get_config_value("ADDR").unwrap();
|
||||
println!("ADDR: {}", v);
|
||||
}
|
||||
@ -3,170 +3,273 @@
|
||||
//! Different PeachCloud microservices import peach-lib, so that they can share
|
||||
//! this interface.
|
||||
//!
|
||||
//! Config values are looked up from three locations in this order by key name:
|
||||
//! 1. from environmental variables
|
||||
//! 2. from a configuration file
|
||||
//! 3. from default values
|
||||
//!
|
||||
//! The configuration file is located at: "/var/lib/peachcloud/config.yml"
|
||||
//! unless its path is configured by setting PEACH_CONFIG_PATH env variable.
|
||||
|
||||
use std::fs;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::{env, fs};
|
||||
|
||||
use fslock::LockFile;
|
||||
use lazy_static::lazy_static;
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::PeachError;
|
||||
|
||||
// main configuration file
|
||||
pub const YAML_PATH: &str = "/var/lib/peachcloud/config.yml";
|
||||
|
||||
// lock file (used to avoid race conditions during config reading & writing)
|
||||
pub const LOCK_FILE_PATH: &str = "/var/lib/peachcloud/config.lock";
|
||||
|
||||
// default values
|
||||
pub const DEFAULT_DYN_SERVER_ADDRESS: &str = "http://dynserver.dyn.peachcloud.org";
|
||||
pub const DEFAULT_DYN_NAMESERVER: &str = "ns.peachcloud.org";
|
||||
|
||||
// we make use of Serde default values in order to make PeachCloud
|
||||
// robust and keep running even with a not fully complete config.yml
|
||||
// main type which represents all peachcloud configurations
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PeachConfig {
|
||||
#[serde(default)]
|
||||
pub external_domain: String,
|
||||
#[serde(default)]
|
||||
pub dyn_domain: String,
|
||||
#[serde(default)]
|
||||
pub dyn_dns_server_address: String,
|
||||
#[serde(default)]
|
||||
pub dyn_use_custom_server: bool,
|
||||
#[serde(default)]
|
||||
pub dyn_nameserver: String,
|
||||
#[serde(default)]
|
||||
pub dyn_tsig_key_path: String,
|
||||
#[serde(default)] // default is false
|
||||
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,
|
||||
// load path to main configuration file
|
||||
// from PEACH_CONFIG_PATH if that environment variable is set
|
||||
// or using the default value if not set
|
||||
pub const DEFAULT_YAML_PATH: &str = "/var/lib/peachcloud/config.yml";
|
||||
lazy_static! {
|
||||
static ref CONFIG_PATH: String = {
|
||||
if let Ok(val) = env::var("PEACH_CONFIG_PATH") {
|
||||
val
|
||||
}
|
||||
else {
|
||||
DEFAULT_YAML_PATH.to_string()
|
||||
}
|
||||
};
|
||||
// lock file (used to avoid race conditions during config reading & writing)
|
||||
// the lock file path is the config file path + ".lock"
|
||||
static ref LOCK_FILE_PATH: String = format!("{}.lock", *CONFIG_PATH);
|
||||
}
|
||||
|
||||
// helper functions for serializing and deserializing PeachConfig from disc
|
||||
pub fn save_peach_config(peach_config: PeachConfig) -> Result<PeachConfig, PeachError> {
|
||||
// Default values for PeachCloud configs which are used for any key which is not set
|
||||
// via an environment variable or in a saved configuration file.
|
||||
pub fn get_peach_config_defaults() -> HashMap<String, String> {
|
||||
let peach_config_defaults: HashMap<String, String> = HashMap::from([
|
||||
("STANDALONE_MODE".to_string(), "true".to_string()),
|
||||
("DISABLE_AUTH".to_string(), "false".to_string()),
|
||||
("ADDR".to_string(), "127.0.0.1".to_string()),
|
||||
("PORT".to_string(), "8000".to_string()),
|
||||
("EXTERNAL_DOMAIN".to_string(), "".to_string()),
|
||||
("DYN_DOMAIN".to_string(), "".to_string()),
|
||||
(
|
||||
"DYN_DNS_SERVER_ADDRESS".to_string(),
|
||||
"http://dynserver.dyn.peachcloud.org".to_string(),
|
||||
),
|
||||
("DYN_USE_CUSTOM_SERVER".to_string(), "true".to_string()),
|
||||
("DYN_TSIG_KEY_PATH".to_string(), "".to_string()),
|
||||
(
|
||||
"DYN_NAMESERVER".to_string(),
|
||||
"ns.peachcloud.org".to_string(),
|
||||
),
|
||||
("DYN_ENABLED".to_string(), "false".to_string()),
|
||||
("SSB_ADMIN_IDS".to_string(), "".to_string()),
|
||||
("ADMIN_PASSWORD_HASH".to_string(), "146".to_string()),
|
||||
("TEMPORARY_PASSWORD_HASH".to_string(), "".to_string()),
|
||||
("GO_SBOT_DATADIR".to_string(), "".to_string()),
|
||||
(
|
||||
"PEACH_CONFIGDIR".to_string(),
|
||||
"/var/lib/peachcloud".to_string(),
|
||||
),
|
||||
]);
|
||||
peach_config_defaults
|
||||
}
|
||||
|
||||
// primary interface for getting config values
|
||||
// Config values are looked up from three locations in this order by key name:
|
||||
// 1. from environmental variables
|
||||
// 2. from a configuration file
|
||||
// 3. from default values
|
||||
pub fn get_config_value(key: &str) -> Result<String, PeachError> {
|
||||
// first check if there is an environmental variable set
|
||||
if let Ok(val) = env::var(key) {
|
||||
Ok(val)
|
||||
} else {
|
||||
// then check if a value is set in the config file
|
||||
let peach_config_on_disc = load_peach_config_from_disc()?;
|
||||
let val = peach_config_on_disc.get(key);
|
||||
// if no value is found in the config file, then get the default value
|
||||
match val {
|
||||
// return config value
|
||||
Some(v) => Ok(v.to_string()),
|
||||
// get default value
|
||||
None => {
|
||||
match get_peach_config_defaults().get(key) {
|
||||
Some(v) => Ok(v.to_string()),
|
||||
// if this key was not found in the defaults, then it was an invalid key
|
||||
None => Err(PeachError::InvalidKey {
|
||||
key: key.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to load PeachCloud configuration file saved to disc
|
||||
pub fn load_peach_config_from_disc() -> Result<HashMap<String, String>, PeachError> {
|
||||
let peach_config_exists = std::path::Path::new(CONFIG_PATH.as_str()).exists();
|
||||
// if config file does not exist, return an emtpy HashMap
|
||||
if !peach_config_exists {
|
||||
let peach_config: HashMap<String, String> = HashMap::new();
|
||||
Ok(peach_config)
|
||||
}
|
||||
// otherwise we load peach config from disk
|
||||
else {
|
||||
debug!("Loading peach config: {} exists", CONFIG_PATH.as_str());
|
||||
let contents =
|
||||
fs::read_to_string(CONFIG_PATH.as_str()).map_err(|source| PeachError::Read {
|
||||
source,
|
||||
path: CONFIG_PATH.to_string(),
|
||||
})?;
|
||||
let peach_config: HashMap<String, String> = serde_yaml::from_str(&contents)?;
|
||||
Ok(peach_config)
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to save PeachCloud configuration file to disc
|
||||
// takes in a Hashmap<String, String> and saves the whole HashMap as a yaml file
|
||||
// with the keys in alphabetical order
|
||||
pub fn save_peach_config_to_disc(
|
||||
peach_config: HashMap<String, String>,
|
||||
) -> Result<HashMap<String, String>, PeachError> {
|
||||
// use a file lock to avoid race conditions while saving config
|
||||
let mut lock = LockFile::open(LOCK_FILE_PATH)?;
|
||||
let mut lock = LockFile::open(&*LOCK_FILE_PATH)?;
|
||||
lock.lock()?;
|
||||
|
||||
let yaml_str = serde_yaml::to_string(&peach_config)?;
|
||||
// first convert Hashmap to BTreeMap (so that keys are saved in deterministic alphabetical order)
|
||||
let ordered: BTreeMap<_, _> = peach_config.iter().collect();
|
||||
// then serialize BTreeMap as yaml
|
||||
let yaml_str = serde_yaml::to_string(&ordered)?;
|
||||
|
||||
fs::write(YAML_PATH, yaml_str).map_err(|source| PeachError::Write {
|
||||
// write yaml to file
|
||||
fs::write(CONFIG_PATH.as_str(), yaml_str).map_err(|source| PeachError::Write {
|
||||
source,
|
||||
path: YAML_PATH.to_string(),
|
||||
path: CONFIG_PATH.to_string(),
|
||||
})?;
|
||||
|
||||
// unlock file lock
|
||||
lock.unlock()?;
|
||||
|
||||
// return peach_config
|
||||
// return modified HashMap
|
||||
Ok(peach_config)
|
||||
}
|
||||
|
||||
pub fn load_peach_config() -> Result<PeachConfig, PeachError> {
|
||||
let peach_config_exists = std::path::Path::new(YAML_PATH).exists();
|
||||
// helper functions for serializing and deserializing PeachConfig values from disc
|
||||
pub fn save_config_value(key: &str, value: &str) -> Result<HashMap<String, String>, PeachError> {
|
||||
// get current config from disc
|
||||
let mut peach_config = load_peach_config_from_disc()?;
|
||||
|
||||
let peach_config: PeachConfig = if !peach_config_exists {
|
||||
debug!("Loading peach config: {} does not exist", YAML_PATH);
|
||||
PeachConfig {
|
||||
external_domain: "".to_string(),
|
||||
dyn_domain: "".to_string(),
|
||||
dyn_dns_server_address: DEFAULT_DYN_SERVER_ADDRESS.to_string(),
|
||||
dyn_use_custom_server: false,
|
||||
dyn_nameserver: DEFAULT_DYN_NAMESERVER.to_string(),
|
||||
dyn_tsig_key_path: "".to_string(),
|
||||
dyn_enabled: false,
|
||||
ssb_admin_ids: Vec::new(),
|
||||
// default password is `peach`
|
||||
admin_password_hash: "146".to_string(),
|
||||
temporary_password_hash: "".to_string(),
|
||||
}
|
||||
}
|
||||
// otherwise we load peach config from disk
|
||||
else {
|
||||
debug!("Loading peach config: {} exists", YAML_PATH);
|
||||
let contents = fs::read_to_string(YAML_PATH).map_err(|source| PeachError::Read {
|
||||
source,
|
||||
path: YAML_PATH.to_string(),
|
||||
})?;
|
||||
serde_yaml::from_str(&contents)?
|
||||
};
|
||||
// insert new key/value
|
||||
peach_config.insert(key.to_string(), value.to_string());
|
||||
|
||||
Ok(peach_config)
|
||||
// save the modified hashmap to disc
|
||||
|
glyph
commented
Tiny typo here on Tiny typo here on `save hte`.
|
||||
save_peach_config_to_disc(peach_config)
|
||||
}
|
||||
|
||||
// interfaces for setting specific config values
|
||||
// set all dyn configuration values at once
|
||||
pub fn set_peach_dyndns_config(
|
||||
dyn_domain: &str,
|
||||
dyn_dns_server_address: &str,
|
||||
dyn_tsig_key_path: &str,
|
||||
dyn_enabled: bool,
|
||||
) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
peach_config.dyn_domain = dyn_domain.to_string();
|
||||
peach_config.dyn_dns_server_address = dyn_dns_server_address.to_string();
|
||||
peach_config.dyn_tsig_key_path = dyn_tsig_key_path.to_string();
|
||||
peach_config.dyn_enabled = dyn_enabled;
|
||||
save_peach_config(peach_config)
|
||||
) -> Result<HashMap<String, String>, PeachError> {
|
||||
let mut peach_config = load_peach_config_from_disc()?;
|
||||
let dyn_enabled_str = match dyn_enabled {
|
||||
true => "true",
|
||||
false => "false",
|
||||
};
|
||||
peach_config.insert("DYN_DOMAIN".to_string(), dyn_domain.to_string());
|
||||
peach_config.insert(
|
||||
"DYN_DNS_SERVER_ADDRESS".to_string(),
|
||||
dyn_dns_server_address.to_string(),
|
||||
);
|
||||
peach_config.insert(
|
||||
"DYN_TSIG_KEY_PATH".to_string(),
|
||||
dyn_tsig_key_path.to_string(),
|
||||
);
|
||||
peach_config.insert("DYN_ENABLED".to_string(), dyn_enabled_str.to_string());
|
||||
save_peach_config_to_disc(peach_config)
|
||||
}
|
||||
|
||||
pub fn set_external_domain(new_external_domain: &str) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
peach_config.external_domain = new_external_domain.to_string();
|
||||
save_peach_config(peach_config)
|
||||
pub fn set_external_domain(
|
||||
new_external_domain: &str,
|
||||
) -> Result<HashMap<String, String>, PeachError> {
|
||||
save_config_value("EXTERNAL_DOMAIN", new_external_domain)
|
||||
}
|
||||
|
||||
pub fn get_peachcloud_domain() -> Result<Option<String>, PeachError> {
|
||||
let peach_config = load_peach_config()?;
|
||||
if !peach_config.external_domain.is_empty() {
|
||||
Ok(Some(peach_config.external_domain))
|
||||
} else if !peach_config.dyn_domain.is_empty() {
|
||||
Ok(Some(peach_config.dyn_domain))
|
||||
let external_domain = get_config_value("EXTERNAL_DOMAIN")?;
|
||||
let dyn_domain = get_config_value("DYN_DOMAIN")?;
|
||||
if !external_domain.is_empty() {
|
||||
Ok(Some(external_domain))
|
||||
} else if !dyn_domain.is_empty() {
|
||||
Ok(Some(dyn_domain))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dyndns_server_address() -> Result<String, PeachError> {
|
||||
let peach_config = load_peach_config()?;
|
||||
// if the user is using a custom dyn server then load the address from the config
|
||||
if peach_config.dyn_use_custom_server {
|
||||
Ok(peach_config.dyn_dns_server_address)
|
||||
}
|
||||
// otherwise hardcode the address
|
||||
else {
|
||||
Ok(DEFAULT_DYN_SERVER_ADDRESS.to_string())
|
||||
get_config_value("DYN_DNS_SERVER_ADDRESS")
|
||||
}
|
||||
|
||||
pub fn set_dyndns_enabled_value(
|
||||
enabled_value: bool,
|
||||
) -> Result<HashMap<String, String>, PeachError> {
|
||||
match enabled_value {
|
||||
true => save_config_value("DYN_ENABLED", "true"),
|
||||
false => save_config_value("DYN_ENABLED", "false"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_dyndns_enabled_value(enabled_value: bool) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
peach_config.dyn_enabled = enabled_value;
|
||||
save_peach_config(peach_config)
|
||||
pub fn get_dyndns_enabled_value() -> Result<bool, PeachError> {
|
||||
let val = get_config_value("DYN_ENABLED")?;
|
||||
Ok(val == "true")
|
||||
}
|
||||
|
||||
pub fn add_ssb_admin_id(ssb_id: &str) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
peach_config.ssb_admin_ids.push(ssb_id.to_string());
|
||||
save_peach_config(peach_config)
|
||||
pub fn set_admin_password_hash(
|
||||
password_hash: String,
|
||||
) -> Result<HashMap<String, String>, PeachError> {
|
||||
save_config_value("ADMIN_PASSWORD_HASH", &password_hash)
|
||||
}
|
||||
|
||||
pub fn delete_ssb_admin_id(ssb_id: &str) -> Result<PeachConfig, PeachError> {
|
||||
let mut peach_config = load_peach_config()?;
|
||||
let mut ssb_admin_ids = peach_config.ssb_admin_ids;
|
||||
pub fn get_admin_password_hash() -> Result<String, PeachError> {
|
||||
let admin_password_hash = get_config_value("ADMIN_PASSWORD_HASH")?;
|
||||
if !admin_password_hash.is_empty() {
|
||||
Ok(admin_password_hash)
|
||||
} else {
|
||||
Err(PeachError::PasswordNotSet)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_temporary_password_hash(
|
||||
password_hash: String,
|
||||
) -> Result<HashMap<String, String>, PeachError> {
|
||||
save_config_value("TEMPORARY_PASSWORD_HASH", &password_hash)
|
||||
}
|
||||
|
||||
pub fn get_temporary_password_hash() -> Result<String, PeachError> {
|
||||
let admin_password_hash = get_config_value("TEMPORARY_PASSWORD_HASH")?;
|
||||
if !admin_password_hash.is_empty() {
|
||||
Ok(admin_password_hash)
|
||||
} else {
|
||||
Err(PeachError::PasswordNotSet)
|
||||
}
|
||||
}
|
||||
|
||||
// add ssb_id to vector of admin ids and save new value for SSB_ADMIN_IDS
|
||||
pub fn add_ssb_admin_id(ssb_id: &str) -> Result<Vec<String>, PeachError> {
|
||||
let mut ssb_admin_ids = get_ssb_admin_ids()?;
|
||||
ssb_admin_ids.push(ssb_id.to_string());
|
||||
save_ssb_admin_ids(ssb_admin_ids)
|
||||
}
|
||||
|
||||
// remove ssb_id from vector of admin ids if found and save new value for SSB_ADMIN_IDS
|
||||
// if value is not found then return an error
|
||||
pub fn delete_ssb_admin_id(ssb_id: &str) -> Result<Vec<String>, PeachError> {
|
||||
let mut ssb_admin_ids = get_ssb_admin_ids()?;
|
||||
let index_result = ssb_admin_ids.iter().position(|x| *x == ssb_id);
|
||||
match index_result {
|
||||
Some(index) => {
|
||||
ssb_admin_ids.remove(index);
|
||||
peach_config.ssb_admin_ids = ssb_admin_ids;
|
||||
save_peach_config(peach_config)
|
||||
save_ssb_admin_ids(ssb_admin_ids)
|
||||
}
|
||||
None => Err(PeachError::SsbAdminIdNotFound {
|
||||
id: ssb_id.to_string(),
|
||||
@ -174,32 +277,16 @@ 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)
|
||||
// looks up the String value for SSB_ADMIN_IDS and converts it into a Vec<String>
|
||||
pub fn get_ssb_admin_ids() -> Result<Vec<String>, PeachError> {
|
||||
let ssb_admin_ids_str = get_config_value("SSB_ADMIN_IDS")?;
|
||||
let ssb_admin_ids: Vec<String> = serde_json::from_str(&ssb_admin_ids_str)?;
|
||||
Ok(ssb_admin_ids)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
// takes in a Vec<String> and saves SSB_ADMIN_IDS as a json string representation of this vec
|
||||
pub fn save_ssb_admin_ids(ssb_admin_ids: Vec<String>) -> Result<Vec<String>, PeachError> {
|
||||
let ssb_admin_ids_as_json_str = serde_json::to_string(&ssb_admin_ids)?;
|
||||
save_config_value("SSB_ADMIN_IDS", &ssb_admin_ids_as_json_str)?;
|
||||
Ok(ssb_admin_ids)
|
||||
}
|
||||
|
||||
@ -18,7 +18,9 @@ use jsonrpc_client_http::HttpTransport;
|
||||
use log::{debug, info};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::config_manager::get_dyndns_server_address;
|
||||
use crate::config_manager::{
|
||||
get_config_value, get_dyndns_enabled_value, get_dyndns_server_address,
|
||||
};
|
||||
use crate::{config_manager, error::PeachError};
|
||||
|
||||
/// constants for dyndns configuration
|
||||
@ -107,7 +109,11 @@ fn get_public_ip_address() -> Result<String, PeachError> {
|
||||
/// Reads dyndns configurations from config.yml
|
||||
/// and then uses nsupdate to update the IP address for the configured domain
|
||||
pub fn dyndns_update_ip() -> Result<bool, PeachError> {
|
||||
let peach_config = config_manager::load_peach_config()?;
|
||||
let dyn_tsig_key_path = get_config_value("DYN_TSIG_KEY_PATH")?;
|
||||
let dyn_enabled = get_dyndns_enabled_value()?;
|
||||
let dyn_domain = get_config_value("DYN_DOMAIN")?;
|
||||
let dyn_dns_server_address = get_config_value("DYN_DNS_SERVER_ADDRESS")?;
|
||||
let dyn_nameserver = get_config_value("DYN_NAMESERVER")?;
|
||||
info!(
|
||||
"Using config:
|
||||
dyn_tsig_key_path: {:?}
|
||||
@ -116,22 +122,15 @@ pub fn dyndns_update_ip() -> Result<bool, PeachError> {
|
||||
dyn_enabled: {:?}
|
||||
dyn_nameserver: {:?}
|
||||
",
|
||||
peach_config.dyn_tsig_key_path,
|
||||
peach_config.dyn_domain,
|
||||
peach_config.dyn_dns_server_address,
|
||||
peach_config.dyn_enabled,
|
||||
peach_config.dyn_nameserver,
|
||||
dyn_tsig_key_path, dyn_domain, dyn_dns_server_address, dyn_enabled, dyn_nameserver,
|
||||
);
|
||||
if !peach_config.dyn_enabled {
|
||||
if !dyn_enabled {
|
||||
info!("dyndns is not enabled, not updating");
|
||||
Ok(false)
|
||||
} else {
|
||||
// call nsupdate passing appropriate configs
|
||||
let mut nsupdate_command = Command::new("nsupdate");
|
||||
nsupdate_command
|
||||
.arg("-k")
|
||||
.arg(&peach_config.dyn_tsig_key_path)
|
||||
.arg("-v");
|
||||
nsupdate_command.arg("-k").arg(&dyn_tsig_key_path).arg("-v");
|
||||
// pass nsupdate commands via stdin
|
||||
let public_ip_address = get_public_ip_address()?;
|
||||
info!("found public ip address: {}", public_ip_address);
|
||||
@ -142,9 +141,9 @@ pub fn dyndns_update_ip() -> Result<bool, PeachError> {
|
||||
update delete {DOMAIN} A
|
||||
update add {DOMAIN} 30 A {PUBLIC_IP_ADDRESS}
|
||||
send",
|
||||
NAMESERVER = peach_config.dyn_nameserver,
|
||||
ZONE = peach_config.dyn_domain,
|
||||
DOMAIN = peach_config.dyn_domain,
|
||||
NAMESERVER = dyn_nameserver,
|
||||
ZONE = dyn_domain,
|
||||
DOMAIN = dyn_domain,
|
||||
PUBLIC_IP_ADDRESS = public_ip_address,
|
||||
);
|
||||
info!("ns_commands: {:?}", ns_commands);
|
||||
@ -217,8 +216,7 @@ pub fn get_num_seconds_since_successful_dns_update() -> Result<Option<i64>, Peac
|
||||
/// and has successfully run recently (in the last six minutes)
|
||||
pub fn is_dns_updater_online() -> Result<bool, PeachError> {
|
||||
// first check if it is enabled in peach-config
|
||||
let peach_config = config_manager::load_peach_config()?;
|
||||
let is_enabled = peach_config.dyn_enabled;
|
||||
let is_enabled = get_dyndns_enabled_value()?;
|
||||
// then check if it has successfully run within the last 6 minutes (60*6 seconds)
|
||||
let num_seconds_since_successful_update = get_num_seconds_since_successful_dns_update()?;
|
||||
let ran_recently: bool = match num_seconds_since_successful_update {
|
||||
@ -248,8 +246,7 @@ pub fn get_dyndns_subdomain(dyndns_full_domain: &str) -> Option<String> {
|
||||
|
||||
// helper function which checks if a dyndns domain is new
|
||||
pub fn check_is_new_dyndns_domain(dyndns_full_domain: &str) -> Result<bool, PeachError> {
|
||||
let peach_config = config_manager::load_peach_config()?;
|
||||
let previous_dyndns_domain = peach_config.dyn_domain;
|
||||
let previous_dyndns_domain = get_config_value("DYN_DOMAIN")?;
|
||||
Ok(dyndns_full_domain != previous_dyndns_domain)
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,12 @@ use std::{io, str, string};
|
||||
/// This type represents all possible errors that can occur when interacting with the PeachCloud library.
|
||||
#[derive(Debug)]
|
||||
pub enum PeachError {
|
||||
/// Represents looking up a Config value with a non-existent key
|
||||
InvalidKey {
|
||||
/// the key value which was invalid
|
||||
key: String,
|
||||
},
|
||||
|
||||
/// Represents a failure to determine the path of the user's home directory.
|
||||
HomeDir,
|
||||
|
||||
@ -102,6 +108,7 @@ impl std::error::Error for PeachError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match *self {
|
||||
PeachError::HomeDir => None,
|
||||
PeachError::InvalidKey { .. } => None,
|
||||
PeachError::Io(_) => None,
|
||||
PeachError::JsonRpcClientCore(_) => None,
|
||||
PeachError::JsonRpcCore(_) => None,
|
||||
@ -130,6 +137,9 @@ impl std::error::Error for PeachError {
|
||||
impl std::fmt::Display for PeachError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match *self {
|
||||
PeachError::InvalidKey { ref key } => {
|
||||
write!(f, "Invalid key in config lookup for key: {}", key)
|
||||
}
|
||||
PeachError::HomeDir => {
|
||||
write!(
|
||||
f,
|
||||
|
||||
@ -33,7 +33,7 @@ pub fn validate_new_passwords(new_password1: &str, new_password2: &str) -> Resul
|
||||
/// Sets 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);
|
||||
config_manager::set_admin_password_hash(&new_password_hash)?;
|
||||
config_manager::set_admin_password_hash(new_password_hash)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -53,7 +53,7 @@ pub fn hash_password(password: &str) -> String {
|
||||
/// 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);
|
||||
config_manager::set_temporary_password_hash(&new_password_hash)?;
|
||||
config_manager::set_temporary_password_hash(new_password_hash)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -103,8 +103,8 @@ using this link: http://peach.local/auth/reset",
|
||||
};
|
||||
msg += &remote_link;
|
||||
// finally send the message to the admins
|
||||
let peach_config = config_manager::load_peach_config()?;
|
||||
for ssb_admin_id in peach_config.ssb_admin_ids {
|
||||
let ssb_admin_ids = config_manager::get_ssb_admin_ids()?;
|
||||
for ssb_admin_id in ssb_admin_ids {
|
||||
// use golgi to send a private message on scuttlebutt
|
||||
match task::block_on(publish_private_msg(&msg, &ssb_admin_id)) {
|
||||
Ok(_) => (),
|
||||
|
||||
@ -26,8 +26,7 @@ use std::{
|
||||
};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use log::{debug, info};
|
||||
use peach_lib::{config_manager, config_manager::YAML_PATH as PEACH_CONFIG};
|
||||
use log::info;
|
||||
|
||||
// crate-local dependencies
|
||||
use config::Config;
|
||||
@ -50,18 +49,6 @@ fn main() {
|
||||
// initialize logger
|
||||
env_logger::init();
|
||||
|
||||
// check if /var/lib/peachcloud/config.yml exists
|
||||
if !std::path::Path::new(PEACH_CONFIG).exists() {
|
||||
debug!("PeachCloud configuration file not found; loading default values");
|
||||
// since we're in the intialisation phase, panic if the loading fails
|
||||
let config =
|
||||
config_manager::load_peach_config().expect("peachcloud configuration loading failed");
|
||||
|
||||
debug!("Saving default PeachCloud configuration values to file");
|
||||
// this ensures a config file is created if it does not already exist
|
||||
config_manager::save_peach_config(config).expect("peachcloud configuration saving failed");
|
||||
}
|
||||
|
||||
// set ip address / hostname and port for the webserver
|
||||
// defaults to "127.0.0.1:8000"
|
||||
let addr_and_port = format!("{}:{}", CONFIG.addr, CONFIG.port);
|
||||
|
||||
@ -13,8 +13,8 @@ pub fn build_template(request: &Request) -> PreEscaped<String> {
|
||||
let (mut flash_name, mut flash_msg) = request.retrieve_flash();
|
||||
|
||||
// attempt to load peachcloud config file
|
||||
let ssb_admins = match config_manager::load_peach_config() {
|
||||
Ok(config) => Some(config.ssb_admin_ids),
|
||||
let ssb_admins = match config_manager::get_ssb_admin_ids() {
|
||||
Ok(ssb_admin_ids) => Some(ssb_admin_ids),
|
||||
// note: this will overwrite any received flash cookie values
|
||||
// TODO: find a way to include the `err` in the flash_msg
|
||||
// currently produces an error because we end up with Some(String)
|
||||
|
||||
Reference in New Issue
Block a user
Could we change this to
1.4? I got into a bad habit of pinning dependencies (specifying them all the way down to the patch version, ie.x.x.x) but I've been trying to undo that.Pinning dependencies increases the likelihood that the compiler needs to compile several versions of the same crate. For example, if we have
lazy_static = "1.4.0"and one of our dependencies useslazy_static = "1.4.1"then both of those will need to be compiled and bundled in our binary.interesting!
in other languages, I've assumed that pinning more precisely is preferrable, because then the library won't "shift under your feet" and change without you realizing (even though with minor number updates its supposed to not be breaking changes, any change is still a possible new bug),
but that makes sense in the rust case specifically it helps reduce compilation time and binary size