You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
3.3 KiB
Rust

use crate::data::node_data::NodeData;
use crate::utils::result::{SnekcloudError, SnekcloudResult};
use crate::utils::settings::get_settings;
use crate::utils::validate_node_id;
use std::fs::create_dir;
use std::path::{Path, PathBuf};
use vented::server::data::Node;
use vented::stream::{PublicKey, SecretKey};
const PRIVATE_KEY_HEADER_LINE: &str = "---BEGIN-SNEKCLOUD-PRIVATE-KEY---\n";
const PRIVATE_KEY_FOOTER_LINE: &str = "\n---END-SNEKCLOUD-PRIVATE-KEY---";
const PUBLIC_KEY_HEADER_LINE: &str = "---BEGIN-SNEKCLOUD-PUBLIC-KEY---\n";
const PUBLIC_KEY_FOOTER_LINE: &str = "\n---END-SNEKCLOUD-PUBLIC-KEY---";
/// Reads a folder of node public keys
pub fn read_node_keys(path: &PathBuf) -> SnekcloudResult<Vec<Node>> {
if !Path::new(path).exists() {
create_dir(path)?;
}
let trusted_nodes = get_settings().trusted_nodes;
let own_id = get_settings().node_id;
let content = glob::glob(format!("{}/*.toml", path.to_string_lossy()).as_str())?
.filter_map(|path| {
let path = path.ok()?;
if path
.file_name()?
.to_string_lossy()
.eq_ignore_ascii_case("local")
{
return None;
}
let data = NodeData::from_file(path).ok()?;
Some(Node {
public_key: data.public_key(),
addresses: data.addresses,
trusted: trusted_nodes.contains(&data.id),
id: data.id,
})
})
.filter(|node| validate_node_id(&node.id) && node.id != own_id)
.collect();
Ok(content)
}
/// Reads the private key from a file
pub fn extract_private_key(content: &str) -> SnekcloudResult<SecretKey> {
let bytes = extract_key(content, PRIVATE_KEY_HEADER_LINE, PRIVATE_KEY_FOOTER_LINE)?;
Ok(SecretKey::from(bytes))
}
/// Reads the public key from a file
pub fn extract_public_key(content: &str) -> SnekcloudResult<PublicKey> {
let bytes = extract_key(content, PUBLIC_KEY_HEADER_LINE, PUBLIC_KEY_FOOTER_LINE)?;
Ok(PublicKey::from(bytes))
}
/// Extracts a base64 encoded key between the prefix and suffix
fn extract_key(content: &str, prefix: &str, suffix: &str) -> SnekcloudResult<[u8; 32]> {
let mut content = content
.strip_prefix(prefix)
.ok_or(SnekcloudError::InvalidKey)?;
content = content
.strip_suffix(suffix)
.ok_or(SnekcloudError::InvalidKey)?;
let key = base64::decode(content)?;
if key.len() != 32 {
return Err(SnekcloudError::InvalidKey);
}
let mut key_bytes = [0u8; 32];
key_bytes.copy_from_slice(&key[..]);
Ok(key_bytes)
}
/// Encodes and encases the public key for text representation
pub fn armor_public_key(key: PublicKey) -> String {
armor_key(
key.to_bytes(),
PUBLIC_KEY_HEADER_LINE,
PUBLIC_KEY_FOOTER_LINE,
)
}
/// Encodes and encases the secret key for text representation
pub fn armor_private_key(key: SecretKey) -> String {
armor_key(
key.to_bytes(),
PRIVATE_KEY_HEADER_LINE,
PRIVATE_KEY_FOOTER_LINE,
)
}
/// Returns an armored key
fn armor_key(key: [u8; 32], prefix: &str, suffix: &str) -> String {
format!("{}{}{}", prefix, base64::encode(key), suffix)
}
/// Generates a new private key
pub fn generate_private_key() -> SecretKey {
SecretKey::generate(&mut rand::thread_rng())
}