summaryrefslogtreecommitdiffhomepage
path: root/mullvad-cli/src
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-07-17 10:36:52 +0200
committerLinus Färnstrand <linus@mullvad.net>2017-07-17 10:48:09 +0200
commitf07f1a0262c908ff83490850b67a167f963efc2d (patch)
tree5a5209baefc0b10ba528f254e7ce2456c23f6ac9 /mullvad-cli/src
parent6a4202fc8c55752f0fef86c04b628a3f9ada5279 (diff)
downloadmullvadvpn-f07f1a0262c908ff83490850b67a167f963efc2d.tar.xz
mullvadvpn-f07f1a0262c908ff83490850b67a167f963efc2d.zip
Rename all crates from snake_case to kebab-case
Diffstat (limited to 'mullvad-cli/src')
-rw-r--r--mullvad-cli/src/cmds/account.rs55
-rw-r--r--mullvad-cli/src/cmds/connect.rs22
-rw-r--r--mullvad-cli/src/cmds/disconnect.rs22
-rw-r--r--mullvad-cli/src/cmds/mod.rs31
-rw-r--r--mullvad-cli/src/cmds/status.rs29
-rw-r--r--mullvad-cli/src/main.rs51
-rw-r--r--mullvad-cli/src/rpc.rs36
7 files changed, 246 insertions, 0 deletions
diff --git a/mullvad-cli/src/cmds/account.rs b/mullvad-cli/src/cmds/account.rs
new file mode 100644
index 0000000000..fcfe9f9901
--- /dev/null
+++ b/mullvad-cli/src/cmds/account.rs
@@ -0,0 +1,55 @@
+use Command;
+use Result;
+use clap;
+use rpc;
+
+pub struct Account;
+
+impl Command for Account {
+ fn name(&self) -> &'static str {
+ "account"
+ }
+
+ fn clap_subcommand(&self) -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name(self.name())
+ .about("Control and display information about your Mullvad account")
+ .setting(clap::AppSettings::SubcommandRequired)
+ .subcommand(clap::SubCommand::with_name("set")
+ .about("Change account")
+ .arg(clap::Arg::with_name("token")
+ .help("The Mullvad account token to configure the client with")
+ .required(true)))
+ .subcommand(clap::SubCommand::with_name("get")
+ .about("Display information about the currently configured account"))
+ }
+
+ fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
+ if let Some(set_matches) = matches.subcommand_matches("set") {
+ let token = value_t_or_exit!(set_matches.value_of("token"), String);
+ self.set(&token)
+ } else if let Some(_matches) = matches.subcommand_matches("get") {
+ self.get()
+ } else {
+ unreachable!("No account command given");
+ }
+ }
+}
+
+impl Account {
+ fn set(&self, token: &str) -> Result<()> {
+ rpc::call("set_account", &[token]).map(
+ |_: Option<()>| {
+ println!("Mullvad account \"{}\" set", token);
+ },
+ )
+ }
+
+ fn get(&self) -> Result<()> {
+ let token: Option<String> = rpc::call("get_account", &[] as &[u8; 0])?;
+ match token {
+ Some(token) => println!("Mullvad account: {:?}", token),
+ None => println!("No account configured"),
+ }
+ Ok(())
+ }
+}
diff --git a/mullvad-cli/src/cmds/connect.rs b/mullvad-cli/src/cmds/connect.rs
new file mode 100644
index 0000000000..4847a0805a
--- /dev/null
+++ b/mullvad-cli/src/cmds/connect.rs
@@ -0,0 +1,22 @@
+use Command;
+use Result;
+use clap;
+use rpc;
+
+pub struct Connect;
+
+impl Command for Connect {
+ fn name(&self) -> &'static str {
+ "connect"
+ }
+
+ fn clap_subcommand(&self) -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name(self.name())
+ .about("Command the client to start establishing a VPN tunnel")
+ }
+
+ fn run(&self, _matches: &clap::ArgMatches) -> Result<()> {
+ let _response: Option<()> = rpc::call("connect", &[] as &[u8; 0])?;
+ Ok(())
+ }
+}
diff --git a/mullvad-cli/src/cmds/disconnect.rs b/mullvad-cli/src/cmds/disconnect.rs
new file mode 100644
index 0000000000..543aa9d0cc
--- /dev/null
+++ b/mullvad-cli/src/cmds/disconnect.rs
@@ -0,0 +1,22 @@
+use Command;
+use Result;
+use clap;
+use rpc;
+
+pub struct Disconnect;
+
+impl Command for Disconnect {
+ fn name(&self) -> &'static str {
+ "disconnect"
+ }
+
+ fn clap_subcommand(&self) -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name(self.name())
+ .about("Command the client to disconnect the VPN tunnel")
+ }
+
+ fn run(&self, _matches: &clap::ArgMatches) -> Result<()> {
+ let _response: Option<()> = rpc::call("disconnect", &[] as &[u8; 0])?;
+ Ok(())
+ }
+}
diff --git a/mullvad-cli/src/cmds/mod.rs b/mullvad-cli/src/cmds/mod.rs
new file mode 100644
index 0000000000..c621c0840a
--- /dev/null
+++ b/mullvad-cli/src/cmds/mod.rs
@@ -0,0 +1,31 @@
+use Command;
+use std::collections::HashMap;
+
+mod account;
+pub use self::account::Account;
+
+mod status;
+pub use self::status::Status;
+
+mod connect;
+pub use self::connect::Connect;
+
+mod disconnect;
+pub use self::disconnect::Disconnect;
+
+/// Returns a map of all available subcommands with their name as key.
+pub fn get_commands() -> HashMap<&'static str, Box<Command>> {
+ let commands: Vec<Box<Command>> = vec![
+ Box::new(Account),
+ Box::new(Status),
+ Box::new(Connect),
+ Box::new(Disconnect),
+ ];
+ let mut map = HashMap::new();
+ for cmd in commands {
+ if let Some(_) = map.insert(cmd.name(), cmd) {
+ panic!("Multiple commands with the same name");
+ }
+ }
+ map
+}
diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs
new file mode 100644
index 0000000000..e02773285f
--- /dev/null
+++ b/mullvad-cli/src/cmds/status.rs
@@ -0,0 +1,29 @@
+use Command;
+use Result;
+use clap;
+
+use mullvad_types::states::{DaemonState, SecurityState, TargetState};
+use rpc;
+
+pub struct Status;
+
+impl Command for Status {
+ fn name(&self) -> &'static str {
+ "status"
+ }
+
+ fn clap_subcommand(&self) -> clap::App<'static, 'static> {
+ clap::SubCommand::with_name(self.name()).about("View the state of the VPN tunnel")
+ }
+
+ fn run(&self, _matches: &clap::ArgMatches) -> Result<()> {
+ let state: DaemonState = rpc::call("get_state", &[] as &[u8; 0])?;
+ match (state.state, state.target_state) {
+ (SecurityState::Unsecured, TargetState::Unsecured) => println!("Disconnected"),
+ (SecurityState::Unsecured, TargetState::Secured) => println!("Connecting..."),
+ (SecurityState::Secured, TargetState::Unsecured) => println!("Disconnecting..."),
+ (SecurityState::Secured, TargetState::Secured) => println!("Connected"),
+ }
+ Ok(())
+ }
+}
diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs
new file mode 100644
index 0000000000..08d5459dd7
--- /dev/null
+++ b/mullvad-cli/src/main.rs
@@ -0,0 +1,51 @@
+// `error_chain!` can recurse deeply
+#![recursion_limit = "1024"]
+
+extern crate mullvad_types;
+extern crate talpid_ipc;
+#[macro_use]
+extern crate clap;
+#[macro_use]
+extern crate error_chain;
+#[macro_use]
+extern crate log;
+extern crate env_logger;
+extern crate serde;
+extern crate serde_json;
+
+mod rpc;
+mod cmds;
+
+
+error_chain!{}
+
+quick_main!(run);
+
+fn run() -> Result<()> {
+ env_logger::init().chain_err(|| "Failed to bootstrap logging system")?;
+
+ let commands = cmds::get_commands();
+
+ let app = clap::App::new(crate_name!())
+ .version(crate_version!())
+ .author(crate_authors!())
+ .about(crate_description!())
+ .setting(clap::AppSettings::SubcommandRequired)
+ .subcommands(commands.values().map(|cmd| cmd.clap_subcommand()));
+
+ let app_matches = app.get_matches();
+ let (subcommand_name, subcommand_matches) = app_matches.subcommand();
+ if let Some(cmd) = commands.get(subcommand_name) {
+ cmd.run(subcommand_matches.expect("No command matched"))
+ } else {
+ unreachable!("No command matched");
+ }
+}
+
+pub trait Command {
+ fn name(&self) -> &'static str;
+
+ fn clap_subcommand(&self) -> clap::App<'static, 'static>;
+
+ fn run(&self, matches: &clap::ArgMatches) -> Result<()>;
+}
diff --git a/mullvad-cli/src/rpc.rs b/mullvad-cli/src/rpc.rs
new file mode 100644
index 0000000000..7397e822c4
--- /dev/null
+++ b/mullvad-cli/src/rpc.rs
@@ -0,0 +1,36 @@
+
+
+use {Result, ResultExt};
+use serde;
+use std::fs::File;
+use std::io::Read;
+use talpid_ipc::WsIpcClient;
+
+pub fn call<T, O>(method: &str, args: &T) -> Result<O>
+ where T: serde::Serialize,
+ O: for<'de> serde::Deserialize<'de>
+{
+ call_internal(method, args).chain_err(|| "Unable to call backend over RPC")
+}
+
+pub fn call_internal<T, O>(method: &str, args: &T) -> Result<O>
+ where T: serde::Serialize,
+ O: for<'de> serde::Deserialize<'de>
+{
+ let address = read_rpc_address()?;
+ info!("Using RPC address {}", address);
+ let mut rpc_client = WsIpcClient::new(address)
+ .chain_err(|| "Unable to create RPC client")?;
+ rpc_client.call(method, args).chain_err(|| format!("Unable to call RPC method {}", method))
+}
+
+fn read_rpc_address() -> Result<String> {
+ let path = ::std::env::temp_dir().join(".mullvad_rpc_address");
+
+ debug!("Trying to read RPC address at {}", path.to_string_lossy());
+ let mut address = String::new();
+ if let Ok(_) = File::open(path).and_then(|mut file| file.read_to_string(&mut address)) {
+ return Ok(address);
+ }
+ bail!("Unable to read RPC address");
+}