diff options
| author | David Lönnhager <david.l@mullvad.net> | 2024-01-10 13:06:03 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2024-01-10 13:06:03 +0100 |
| commit | 75eb89c820f12d488a76934f59ba29fe999cf59c (patch) | |
| tree | dee82ab3f307f8d1a72a0cf01fceb8fa51612ac1 /mullvad-cli/src/cmds | |
| parent | edbd1f52c44ba6ee9a290146f714453fc87e689d (diff) | |
| parent | 01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d (diff) | |
| download | mullvadvpn-75eb89c820f12d488a76934f59ba29fe999cf59c.tar.xz mullvadvpn-75eb89c820f12d488a76934f59ba29fe999cf59c.zip | |
Merge branch 'add-settings-json-export'
Diffstat (limited to 'mullvad-cli/src/cmds')
| -rw-r--r-- | mullvad-cli/src/cmds/import_settings.rs | 101 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/mod.rs | 2 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/patch.rs | 60 |
3 files changed, 61 insertions, 102 deletions
diff --git a/mullvad-cli/src/cmds/import_settings.rs b/mullvad-cli/src/cmds/import_settings.rs deleted file mode 100644 index a89c6814c3..0000000000 --- a/mullvad-cli/src/cmds/import_settings.rs +++ /dev/null @@ -1,101 +0,0 @@ -use anyhow::{anyhow, Context, Result}; -use mullvad_management_interface::MullvadProxyClient; -use std::{ - fs::File, - io::{stdin, BufRead, BufReader}, - path::Path, -}; - -/// Maximum size of a settings patch. Bigger files/streams cause the read to fail. -const MAX_PATCH_BYTES: usize = 10 * 1024; - -/// If source is specified, read from the provided file and send it as a settings patch to the -/// daemon. Otherwise, read the patch from standard input. -pub async fn handle(source: String) -> Result<()> { - let json_blob = tokio::task::spawn_blocking(|| get_blob(source)) - .await - .unwrap()?; - - let mut rpc = MullvadProxyClient::new().await?; - rpc.apply_json_settings(json_blob) - .await - .context("Error applying patch")?; - - println!("Settings applied"); - - Ok(()) -} - -fn get_blob(source: String) -> Result<String> { - match source.as_str() { - "-" => read_settings_from_stdin().context("Failed to read from stdin"), - _ => read_settings_from_file(source).context("Failed to read from path: {source}"), - } -} - -/// Read settings from standard input -fn read_settings_from_stdin() -> Result<String> { - read_settings_from_reader(BufReader::new(stdin())) -} - -/// Read settings from a path -fn read_settings_from_file(path: impl AsRef<Path>) -> Result<String> { - read_settings_from_reader(BufReader::new(File::open(path)?)) -} - -/// Read until EOF or until newline when the last pair of braces has been closed -fn read_settings_from_reader(mut reader: impl BufRead) -> Result<String> { - let mut buf = [0u8; MAX_PATCH_BYTES]; - - let mut was_open = false; - let mut close_after_newline = false; - let mut brace_count: usize = 0; - let mut cursor_pos = 0; - - loop { - let Some(cursor) = buf.get_mut(cursor_pos..) else { - return Err(anyhow!( - "Patch too long: maximum length is {MAX_PATCH_BYTES} bytes" - )); - }; - - let prev_cursor_pos = cursor_pos; - let read_n = reader.read(cursor)?; - if read_n == 0 { - // EOF - break; - } - cursor_pos += read_n; - - let additional_bytes = &buf[prev_cursor_pos..cursor_pos]; - - if !close_after_newline { - for next in additional_bytes { - match next { - b'{' => brace_count += 1, - b'}' => { - brace_count = brace_count.checked_sub(1).with_context(|| { - // exit: too many closing braces - "syntax error: unexpected '}'" - })? - } - _ => (), - } - was_open |= brace_count > 0; - } - if brace_count == 0 && was_open { - // complete settings - close_after_newline = true; - } - } - - if close_after_newline && additional_bytes.contains(&b'\n') { - // done - break; - } - } - - Ok(std::str::from_utf8(&buf[0..cursor_pos]) - .context("settings must be utf8 encoded")? - .to_owned()) -} diff --git a/mullvad-cli/src/cmds/mod.rs b/mullvad-cli/src/cmds/mod.rs index 29e0508d80..5a9cede691 100644 --- a/mullvad-cli/src/cmds/mod.rs +++ b/mullvad-cli/src/cmds/mod.rs @@ -9,10 +9,10 @@ pub mod bridge; pub mod custom_list; pub mod debug; pub mod dns; -pub mod import_settings; pub mod lan; pub mod lockdown; pub mod obfuscation; +pub mod patch; pub mod proxies; pub mod relay; pub mod relay_constraints; diff --git a/mullvad-cli/src/cmds/patch.rs b/mullvad-cli/src/cmds/patch.rs new file mode 100644 index 0000000000..bec686e56d --- /dev/null +++ b/mullvad-cli/src/cmds/patch.rs @@ -0,0 +1,60 @@ +use anyhow::{Context, Result}; +use mullvad_management_interface::MullvadProxyClient; +use std::{ + fs::File, + io::{stdin, BufReader, Read}, +}; + +/// If source is specified, read from the provided file and send it as a settings patch to the +/// daemon. Otherwise, read the patch from standard input. +pub async fn import(source: String) -> Result<()> { + let json_blob = tokio::task::spawn_blocking(|| get_blob(source)) + .await + .unwrap()?; + + let mut rpc = MullvadProxyClient::new().await?; + rpc.apply_json_settings(json_blob) + .await + .context("Error applying patch")?; + + println!("Settings applied"); + + Ok(()) +} + +/// If source is specified, write a patch to the file. Otherwise, write the patch to standard +/// output. +pub async fn export(dest: String) -> Result<()> { + let mut rpc = MullvadProxyClient::new().await?; + let blob = rpc + .export_json_settings() + .await + .context("Error exporting patch")?; + + match dest.as_str() { + "-" => { + println!("{blob}"); + Ok(()) + } + _ => tokio::fs::write(&dest, blob) + .await + .context(format!("Failed to write to path {dest}")), + } +} + +fn get_blob(source: String) -> Result<String> { + match source.as_str() { + "-" => { + read_settings_from_reader(BufReader::new(stdin())).context("Failed to read from stdin") + } + _ => read_settings_from_reader(File::open(&source)?) + .context(format!("Failed to read from path: {source}")), + } +} + +/// Read until EOF or until newline when the last pair of braces has been closed +fn read_settings_from_reader(mut reader: impl Read) -> Result<String> { + let mut s = String::new(); + reader.read_to_string(&mut s)?; + Ok(s) +} |
