shared: proactively create invite file to ensure we have permission
This won't clean up an empty file if a later step fails, but this is still better than the previous solution. Closes #91pull/121/head
parent
8bd7b6e283
commit
647ec7ca3e
|
@ -614,21 +614,23 @@ fn add_peer(interface: &InterfaceName, opts: AddPeerOpts) -> Result<(), Error> {
|
|||
let peers: Vec<Peer> = api.http("GET", "/admin/peers")?;
|
||||
let cidr_tree = CidrTree::new(&cidrs[..]);
|
||||
|
||||
if let Some((peer_request, keypair)) = prompts::add_peer(&peers, &cidr_tree, &opts)? {
|
||||
if let Some(result) = prompts::add_peer(&peers, &cidr_tree, &opts)? {
|
||||
let (peer_request, keypair, target_path, mut target_file) = result;
|
||||
log::info!("Creating peer...");
|
||||
let peer: Peer = api.http_form("POST", "/admin/peers", peer_request)?;
|
||||
let server_peer = peers.iter().find(|p| p.id == 1).unwrap();
|
||||
prompts::save_peer_invitation(
|
||||
prompts::write_peer_invitation(
|
||||
&mut target_file,
|
||||
&target_path,
|
||||
interface,
|
||||
&peer,
|
||||
server_peer,
|
||||
&cidr_tree,
|
||||
keypair,
|
||||
&server.internal_endpoint,
|
||||
&opts.save_config,
|
||||
)?;
|
||||
} else {
|
||||
log::info!("exited without creating peer.");
|
||||
log::info!("Exited without creating peer.");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -293,7 +293,8 @@ fn add_peer(
|
|||
let cidrs = DatabaseCidr::list(&conn)?;
|
||||
let cidr_tree = CidrTree::new(&cidrs[..]);
|
||||
|
||||
if let Some((peer_request, keypair)) = shared::prompts::add_peer(&peers, &cidr_tree, &opts)? {
|
||||
if let Some(result) = shared::prompts::add_peer(&peers, &cidr_tree, &opts)? {
|
||||
let (peer_request, keypair, target_path, mut target_file) = result;
|
||||
let peer = DatabasePeer::create(&conn, peer_request)?;
|
||||
if cfg!(not(test)) && Device::get(interface, network.backend).is_ok() {
|
||||
// Update the current WireGuard interface with the new peers.
|
||||
|
@ -306,14 +307,15 @@ fn add_peer(
|
|||
}
|
||||
|
||||
let server_peer = DatabasePeer::get(&conn, 1)?;
|
||||
prompts::save_peer_invitation(
|
||||
prompts::write_peer_invitation(
|
||||
&mut target_file,
|
||||
&target_path,
|
||||
interface,
|
||||
&peer,
|
||||
&*server_peer,
|
||||
&cidr_tree,
|
||||
keypair,
|
||||
&SocketAddr::new(config.address, config.listen_port),
|
||||
&opts.save_config,
|
||||
)?;
|
||||
} else {
|
||||
println!("exited without creating peer.");
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
use crate::{ensure_dirs_exist, Endpoint, Error, IoErrorContext, CLIENT_CONFIG_DIR};
|
||||
use colored::*;
|
||||
use crate::{CLIENT_CONFIG_DIR, Endpoint, Error, IoErrorContext, WrappedIoError, ensure_dirs_exist};
|
||||
use indoc::writedoc;
|
||||
use ipnetwork::IpNetwork;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::Write,
|
||||
net::SocketAddr,
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::{fs::{File, OpenOptions}, io::{self, Write}, net::SocketAddr, os::unix::fs::PermissionsExt, path::{Path, PathBuf}};
|
||||
use wgctrl::InterfaceName;
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
||||
|
@ -53,26 +46,13 @@ pub struct ServerInfo {
|
|||
}
|
||||
|
||||
impl InterfaceConfig {
|
||||
pub fn write_to_path<P: AsRef<Path>>(
|
||||
pub fn write_to(
|
||||
&self,
|
||||
path: P,
|
||||
target_file: &mut File,
|
||||
comments: bool,
|
||||
mode: Option<u32>,
|
||||
) -> Result<(), Error> {
|
||||
let path = path.as_ref();
|
||||
let mut target_file = OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(path)
|
||||
.with_path(path)?;
|
||||
) -> Result<(), io::Error> {
|
||||
if let Some(val) = mode {
|
||||
if crate::chmod(&target_file, 0o600)? {
|
||||
println!(
|
||||
"{} updated permissions for {} to 0600.",
|
||||
"[!]".yellow(),
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
let metadata = target_file.metadata()?;
|
||||
let mut permissions = metadata.permissions();
|
||||
permissions.set_mode(val);
|
||||
|
@ -96,11 +76,25 @@ impl InterfaceConfig {
|
|||
)?;
|
||||
}
|
||||
target_file
|
||||
.write_all(toml::to_string(self).unwrap().as_bytes())
|
||||
.with_path(path)?;
|
||||
.write_all(toml::to_string(self).unwrap().as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_to_path<P: AsRef<Path>>(
|
||||
&self,
|
||||
path: P,
|
||||
comments: bool,
|
||||
mode: Option<u32>,
|
||||
) -> Result<(), WrappedIoError> {
|
||||
let path = path.as_ref();
|
||||
let mut target_file = OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(path)
|
||||
.with_path(path)?;
|
||||
self.write_to(&mut target_file, comments, mode).with_path(path)
|
||||
}
|
||||
|
||||
/// Overwrites the config file if it already exists.
|
||||
pub fn write_to_interface(&self, interface: &InterfaceName) -> Result<PathBuf, Error> {
|
||||
let path = Self::build_config_file_path(interface)?;
|
||||
|
|
|
@ -9,13 +9,7 @@ use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
|
|||
use ipnetwork::IpNetwork;
|
||||
use lazy_static::lazy_static;
|
||||
use publicip::Preference;
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
io,
|
||||
net::SocketAddr,
|
||||
str::FromStr,
|
||||
time::SystemTime,
|
||||
};
|
||||
use std::{fmt::{Debug, Display}, fs::{File, OpenOptions}, io, net::SocketAddr, str::FromStr, time::SystemTime};
|
||||
use wgctrl::{InterfaceName, KeyPair};
|
||||
|
||||
lazy_static! {
|
||||
|
@ -206,7 +200,7 @@ pub fn add_peer(
|
|||
peers: &[Peer],
|
||||
cidr_tree: &CidrTree,
|
||||
args: &AddPeerOpts,
|
||||
) -> Result<Option<(PeerContents, KeyPair)>, Error> {
|
||||
) -> Result<Option<(PeerContents, KeyPair, String, File)>, Error> {
|
||||
let leaves = cidr_tree.leaves();
|
||||
|
||||
let cidr = if let Some(ref parent_name) = args.cidr {
|
||||
|
@ -255,6 +249,12 @@ pub fn add_peer(
|
|||
input("Invite expires after", Prefill::Default("14d".parse().map_err(|s: &str| anyhow!(s))?))?
|
||||
};
|
||||
|
||||
let invite_save_path = if let Some(ref location) = args.save_config {
|
||||
location.clone()
|
||||
} else {
|
||||
input("Save peer invitation file to", Prefill::Default(format!("{}.toml", name)))?
|
||||
};
|
||||
|
||||
let default_keypair = KeyPair::generate();
|
||||
let peer_request = PeerContents {
|
||||
name,
|
||||
|
@ -271,7 +271,12 @@ pub fn add_peer(
|
|||
|
||||
Ok(
|
||||
if args.yes || confirm(&format!("Create peer {}?", peer_request.name.yellow()))? {
|
||||
Some((peer_request, default_keypair))
|
||||
let invite_file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&invite_save_path)?;
|
||||
Some((peer_request, default_keypair, invite_save_path, invite_file))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
|
@ -360,14 +365,15 @@ pub fn enable_or_disable_peer(peers: &[Peer], enable: bool) -> Result<Option<Pee
|
|||
}
|
||||
|
||||
/// Confirm and write a innernet invitation file after a peer has been created.
|
||||
pub fn save_peer_invitation(
|
||||
pub fn write_peer_invitation(
|
||||
target_file: &mut File,
|
||||
target_path: &str,
|
||||
network_name: &InterfaceName,
|
||||
peer: &Peer,
|
||||
server_peer: &Peer,
|
||||
root_cidr: &Cidr,
|
||||
keypair: KeyPair,
|
||||
server_api_addr: &SocketAddr,
|
||||
config_location: &Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
let peer_invitation = InterfaceConfig {
|
||||
interface: InterfaceInfo {
|
||||
|
@ -386,13 +392,7 @@ pub fn save_peer_invitation(
|
|||
},
|
||||
};
|
||||
|
||||
let invitation_save_path = if let Some(location) = config_location {
|
||||
location.clone()
|
||||
} else {
|
||||
input("Save peer invitation file as", Prefill::Default(format!("{}.toml", peer.name)))?
|
||||
};
|
||||
|
||||
peer_invitation.write_to_path(&invitation_save_path, true, None)?;
|
||||
peer_invitation.write_to(target_file, true, None)?;
|
||||
|
||||
println!(
|
||||
"\nPeer \"{}\" added\n\
|
||||
|
@ -400,7 +400,7 @@ pub fn save_peer_invitation(
|
|||
Please send it to them securely (eg. via magic-wormhole) \
|
||||
to bootstrap them onto the network.",
|
||||
peer.name.bold(),
|
||||
invitation_save_path.bold()
|
||||
target_path.bold()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in New Issue