Save tokens for each machine

This commit is contained in:
Andrey Golovizin 2023-04-15 13:34:25 +02:00
parent 4e62839513
commit 6c6d5a51a8
3 changed files with 83 additions and 27 deletions

View file

@ -1,7 +1,8 @@
use directories::ProjectDirs; use directories::ProjectDirs;
use gethostname::gethostname;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::path::PathBuf; use std::path::{Path, PathBuf};
const QUALIFIER: &str = "com"; const QUALIFIER: &str = "com";
const ORGANIZATION: &str = "Ero-sennin"; const ORGANIZATION: &str = "Ero-sennin";
@ -16,3 +17,43 @@ pub(crate) fn get_data_dir() -> PathBuf {
}); });
project_dirs.data_dir().to_path_buf() project_dirs.data_dir().to_path_buf()
} }
pub(crate) struct MachineConfig {
path: PathBuf,
}
impl MachineConfig {
pub(crate) fn new(machine_name: Option<&PathBuf>) -> anyhow::Result<Self> {
let hostname: PathBuf;
let machine: &PathBuf = if let Some(machine_name) = machine_name {
machine_name
} else {
hostname = PathBuf::from(gethostname());
&hostname
};
let path = get_data_dir().join("machines").join(machine);
std::fs::create_dir_all(&path)?;
Ok(Self { path })
}
pub(crate) fn destroy(self) -> anyhow::Result<()> {
std::fs::remove_dir_all(self.path)?;
Ok(())
}
pub(crate) fn path(&self) -> &Path {
&self.path
}
pub(crate) fn username_path(&self) -> PathBuf {
self.path().join("username")
}
pub(crate) fn token_path(&self) -> PathBuf {
self.path().join("token")
}
pub(crate) fn key_path(&self) -> PathBuf {
self.path().join("key")
}
}

View file

@ -1,14 +1,10 @@
use base64::prelude::{Engine as _, BASE64_STANDARD}; use base64::prelude::{Engine as _, BASE64_STANDARD};
use gethostname::gethostname;
use log::debug; use log::debug;
use x25519_dalek::{PublicKey, StaticSecret}; use x25519_dalek::{PublicKey, StaticSecret};
use std::{ use std::{io::Write, path::Path};
io::Write,
path::{Path, PathBuf},
};
use crate::dirs::get_data_dir; use crate::dirs::MachineConfig;
const KEY_SIZE: usize = 32; const KEY_SIZE: usize = 32;
@ -46,24 +42,15 @@ pub(crate) struct WireguardKeyPair {
pub private_key: Key, pub private_key: Key,
} }
pub(crate) fn get_keys(machine: Option<&PathBuf>) -> Result<WireguardKeyPair, anyhow::Error> { pub(crate) fn get_keys(machine_config: &MachineConfig) -> Result<WireguardKeyPair, anyhow::Error> {
let hostname: PathBuf; let key_path = machine_config.key_path();
let machine_subdir: &PathBuf = if let Some(machine) = machine {
machine
} else {
hostname = PathBuf::from(gethostname());
&hostname
};
let key_path = get_data_dir().join("keys");
debug!("key path = {:?}", &key_path); debug!("key path = {:?}", &key_path);
std::fs::create_dir_all(&key_path)?;
let private_key_path = key_path.join(machine_subdir); let private_key = if key_path.is_file() {
let private_key = if private_key_path.is_file() { Key::load(&key_path)?
Key::load(&private_key_path)?
} else { } else {
let key = generate_private_key(); let key = generate_private_key();
key.save(&private_key_path)?; key.save(&key_path)?;
key key
}; };

View file

@ -1,15 +1,15 @@
mod api; mod api;
use std::net::IpAddr;
mod dirs; mod dirs;
mod keys; mod keys;
use std::io::Write; use std::io::Write;
use std::net::IpAddr;
use std::path::PathBuf; use std::path::PathBuf;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use log::debug; use log::debug;
use crate::keys::{get_keys, WireguardKeyPair}; use crate::{keys::{get_keys, WireguardKeyPair}, dirs::MachineConfig};
/// AzireVPN client /// AzireVPN client
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -27,10 +27,14 @@ struct Opts {
} }
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct ConfigOpts { struct LoginOpts {
location: String,
username: String, username: String,
token: String, token: String,
}
#[derive(Parser, Debug)]
struct ConfigOpts {
location: String,
#[arg(short, long)] #[arg(short, long)]
no_dns: bool, no_dns: bool,
@ -41,6 +45,12 @@ struct ConfigOpts {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum Command { enum Command {
/// Add machine token
Login(LoginOpts),
/// Logout
Logout,
/// Checks connection status /// Checks connection status
Check, Check,
@ -55,6 +65,8 @@ fn main() -> Result<(), anyhow::Error> {
env_logger::init(); env_logger::init();
let opts = Opts::parse(); let opts = Opts::parse();
match &opts.command { match &opts.command {
Command::Login(login_opts) => login(&opts, login_opts)?,
Command::Logout => logout(&opts)?,
Command::Check => check(&opts)?, Command::Check => check(&opts)?,
Command::Locations => list_locations(&opts)?, Command::Locations => list_locations(&opts)?,
Command::Config(get_config_opts) => get_config(&opts, get_config_opts)?, Command::Config(get_config_opts) => get_config(&opts, get_config_opts)?,
@ -62,6 +74,19 @@ fn main() -> Result<(), anyhow::Error> {
Ok(()) Ok(())
} }
fn login(opts: &Opts, login_opts: &LoginOpts) -> Result<(), anyhow::Error> {
let machine_config = dirs::MachineConfig::new(opts.machine.as_ref())?;
std::fs::write(machine_config.username_path(), &login_opts.username)?;
std::fs::write(machine_config.token_path(), &login_opts.token)?;
Ok(())
}
fn logout(opts: &Opts) -> Result<(), anyhow::Error> {
let machine_config = dirs::MachineConfig::new(opts.machine.as_ref())?;
machine_config.destroy()?;
Ok(())
}
fn check(opts: &Opts) -> Result<(), anyhow::Error> { fn check(opts: &Opts) -> Result<(), anyhow::Error> {
let check_result = api::check()?; let check_result = api::check()?;
if opts.json { if opts.json {
@ -97,6 +122,7 @@ fn list_locations(opts: &Opts) -> Result<(), anyhow::Error> {
} }
fn get_config(opts: &Opts, config_opts: &ConfigOpts) -> Result<(), anyhow::Error> { fn get_config(opts: &Opts, config_opts: &ConfigOpts) -> Result<(), anyhow::Error> {
let machine_config = MachineConfig::new(opts.machine.as_ref())?;
let locations = api::get_locations()?; let locations = api::get_locations()?;
let location = locations let location = locations
.locations .locations
@ -104,9 +130,11 @@ fn get_config(opts: &Opts, config_opts: &ConfigOpts) -> Result<(), anyhow::Error
.find(|location| location.name == config_opts.location) .find(|location| location.name == config_opts.location)
.ok_or_else(|| anyhow::anyhow!("no such location: {}", config_opts.location))?; .ok_or_else(|| anyhow::anyhow!("no such location: {}", config_opts.location))?;
debug!("location = {:?}", &location); debug!("location = {:?}", &location);
let keys = get_keys(opts.machine.as_ref())?; let keys = get_keys(&machine_config)?;
let username = std::fs::read_to_string(machine_config.username_path())?;
let token = std::fs::read_to_string(machine_config.token_path())?;
debug!("keys = {:?}", &keys); debug!("keys = {:?}", &keys);
let addresses = api::add_ip(&config_opts.username, &config_opts.token, &keys.public_key)?; let addresses = api::add_ip(&username, &token, &keys.public_key)?;
write_config( write_config(
&mut std::io::stdout().lock(), &mut std::io::stdout().lock(),