diff --git a/Cargo.lock b/Cargo.lock index a1ce26b..987773b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1026,9 +1026,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] diff --git a/src/api.rs b/src/api.rs index 67677fa..032ae94 100644 --- a/src/api.rs +++ b/src/api.rs @@ -3,6 +3,8 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use log::debug; use serde::{Deserialize, Serialize}; +use crate::keys::Key; + const BASE_URL: &str = "https://api.azirevpn.com"; #[derive(Serialize, Deserialize, Debug)] @@ -60,13 +62,13 @@ pub(crate) fn get_locations() -> anyhow::Result { Ok(response) } -pub(crate) fn add_ip(username: &str, token: &str, public_key: &str) -> anyhow::Result { +pub(crate) fn add_ip(username: &str, token: &str, public_key: &Key) -> anyhow::Result { let url = format!("{}/v2/ip/add", BASE_URL); let response: Addresses = ureq::post(&url) .send_form(&[ ("username", username), ("token", token), - ("key", public_key), + ("key", &public_key.to_base64()), ])? .into_json()?; debug!("response = {:?}", &response); diff --git a/src/keys.rs b/src/keys.rs index eb0036e..a5b5248 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -3,16 +3,43 @@ use gethostname::gethostname; use log::debug; use x25519_dalek::{PublicKey, StaticSecret}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use crate::dirs::get_data_dir; const KEY_SIZE: usize = 32; +#[derive(Debug)] +pub(crate) struct Key([u8; KEY_SIZE]); + +impl Key { + fn try_from_base64(data: &str) -> anyhow::Result { + let mut key_data = [0u8; KEY_SIZE]; + let key_bytes = BASE64_STANDARD.decode(data)?; + assert_eq!(key_bytes.len(), KEY_SIZE); + key_data[0..KEY_SIZE].copy_from_slice(&key_bytes); + Ok(Self(key_data)) + } + + pub(crate) fn to_base64(&self) -> String { + BASE64_STANDARD.encode(self.0) + } + + fn read(path: &Path) -> anyhow::Result { + let key_data = std::fs::read_to_string(path)?; + Self::try_from_base64(&key_data) + } + + fn write(&self, path: &Path) -> anyhow::Result<()> { + std::fs::write(path, self.to_base64())?; + Ok(()) + } +} + #[derive(Debug)] pub(crate) struct WireguardKeyPair { - pub public_key: String, - pub private_key: String, + pub public_key: Key, + pub private_key: Key, } pub(crate) fn get_keys(machine: Option<&PathBuf>) -> Result { @@ -28,18 +55,18 @@ pub(crate) fn get_keys(machine: Option<&PathBuf>) -> Result) -> Result anyhow::Result { - let private_key = StaticSecret::random(); - Ok(BASE64_STANDARD.encode(private_key.to_bytes())) +fn generate_private_key() -> Key { + Key(StaticSecret::random().to_bytes()) } -fn generate_public_key(private_key: &str) -> anyhow::Result { - let mut key_data = [0u8; KEY_SIZE]; - let key_bytes = BASE64_STANDARD.decode(private_key)?; - assert_eq!(key_bytes.len(), KEY_SIZE); - key_data[0..KEY_SIZE].copy_from_slice(&key_bytes); - let key = StaticSecret::from(key_data); +fn generate_public_key(private_key: &Key) -> Key { + let key = StaticSecret::from(private_key.0); let pubkey = PublicKey::from(&key); - Ok(BASE64_STANDARD.encode(pubkey.to_bytes())) + Key(pubkey.to_bytes()) } diff --git a/src/main.rs b/src/main.rs index e5877d4..4fe581e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -125,7 +125,7 @@ fn write_config( keys: &WireguardKeyPair, ) -> Result<(), anyhow::Error> { writeln!(output, "[Interface]")?; - writeln!(output, "PrivateKey = {}", &keys.private_key)?; + writeln!(output, "PrivateKey = {}", &keys.private_key.to_base64())?; let allowed_addresses = if config_opts.no_ipv6 { vec![IpAddr::V4(config.ipv4.address)] } else {