summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-10-30 14:59:46 +0100
committerLinus Färnstrand <linus@mullvad.net>2017-10-30 14:59:46 +0100
commit3df28edf3258b3de877a14becac237e413978e02 (patch)
treed5dc489b8d3360bafcaa7b6eae1bd59e0be5f749
parenta9379bf7c5628abdac284857c200e9f19346ef29 (diff)
parent7cce6e4f1f3d3b088ae383673881067f90b09443 (diff)
downloadmullvadvpn-3df28edf3258b3de877a14becac237e413978e02.tar.xz
mullvadvpn-3df28edf3258b3de877a14becac237e413978e02.zip
Merge branch 'problem-report-send'
-rw-r--r--Cargo.lock13
-rw-r--r--Cargo.toml1
-rw-r--r--mullvad-cli/src/main.rs3
-rw-r--r--mullvad-daemon/Cargo.toml3
-rw-r--r--mullvad-daemon/src/bin/problem-report.rs116
-rw-r--r--mullvad-daemon/src/main.rs13
-rw-r--r--mullvad-daemon/src/management_interface.rs10
-rw-r--r--mullvad-daemon/src/master.rs16
-rw-r--r--mullvad-rpc/Cargo.toml13
-rw-r--r--mullvad-rpc/src/lib.rs49
10 files changed, 140 insertions, 97 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f080a8e078..d0c58be2c7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -673,14 +673,13 @@ dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fern 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-client-core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-client-http 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 7.1.1 (git+https://github.com/paritytech/jsonrpc?tag=v7.1.1)",
"jsonrpc-macros 7.1.1 (git+https://github.com/paritytech/jsonrpc?tag=v7.1.1)",
"jsonrpc-pubsub 7.1.1 (git+https://github.com/paritytech/jsonrpc?tag=v7.1.1)",
"jsonrpc-ws-server 7.1.1 (git+https://github.com/paritytech/jsonrpc?tag=v7.1.1)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mullvad-rpc 0.1.0",
"mullvad-types 0.1.0",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -693,6 +692,16 @@ dependencies = [
]
[[package]]
+name = "mullvad-rpc"
+version = "0.1.0"
+dependencies = [
+ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-http 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mullvad-types 0.1.0",
+]
+
+[[package]]
name = "mullvad-types"
version = "0.1.0"
dependencies = [
diff --git a/Cargo.toml b/Cargo.toml
index e5bf17fc21..0082f61236 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,7 @@ members = [
"mullvad-daemon",
"mullvad-cli",
"mullvad-types",
+ "mullvad-rpc",
"talpid-openvpn-plugin",
"talpid-core",
"talpid-ipc",
diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs
index 274f1cc60f..e3475888fa 100644
--- a/mullvad-cli/src/main.rs
+++ b/mullvad-cli/src/main.rs
@@ -6,9 +6,6 @@
//! GNU General Public License as published by the Free Software Foundation, either version 3 of
//! the License, or (at your option) any later version.
-// `error_chain!` can recurse deeply
-#![recursion_limit = "1024"]
-
#[macro_use]
extern crate clap;
extern crate env_logger;
diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml
index 6dbd3430b0..7449b9120e 100644
--- a/mullvad-daemon/Cargo.toml
+++ b/mullvad-daemon/Cargo.toml
@@ -28,13 +28,12 @@ jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc", tag = "v7.1.1" }
-jsonrpc-client-core = "0.2.1"
-jsonrpc-client-http = "0.2.1"
uuid = { version = "0.5", features = ["v4"] }
lazy_static = "0.2"
toml = "0.4"
mullvad-types = { path = "../mullvad-types" }
+mullvad-rpc = { path = "../mullvad-rpc" }
talpid-core = { path = "../talpid-core" }
talpid-ipc = { path = "../talpid-ipc" }
talpid-types = { path = "../talpid-types" }
diff --git a/mullvad-daemon/src/bin/problem-report.rs b/mullvad-daemon/src/bin/problem-report.rs
index a4b5107dec..8ecae0a0e5 100644
--- a/mullvad-daemon/src/bin/problem-report.rs
+++ b/mullvad-daemon/src/bin/problem-report.rs
@@ -11,6 +11,8 @@ extern crate clap;
#[macro_use]
extern crate error_chain;
+extern crate mullvad_rpc;
+
use error_chain::ChainedError;
use std::cmp::min;
use std::fmt;
@@ -20,6 +22,9 @@ use std::path::{Path, PathBuf};
/// Maximum number of bytes to read from each log file
const LOG_MAX_READ_BYTES: usize = 5 * 1024 * 1024;
+/// Maximum number of bytes allowed in a report.
+const REPORT_MAX_SIZE: usize = 4 * LOG_MAX_READ_BYTES;
+
/// Field delimeter in generated problem report
const LOG_DELIMITER: &'static str = "====================";
@@ -34,6 +39,9 @@ error_chain!{
description("Error reading the contents of log file")
display("Error reading the contents of log file: {}", path.to_string_lossy())
}
+ RpcError {
+ description("Error during RPC call")
+ }
}
}
@@ -96,40 +104,40 @@ fn run() -> Result<()> {
let matches = app.get_matches();
if let Some(collect_matches) = matches.subcommand_matches("collect") {
- let log_paths = values_t!(collect_matches.values_of("logs"), String)
- .unwrap_or(Vec::new())
- .iter()
- .map(PathBuf::from)
- .collect();
- let output_path = value_t_or_exit!(collect_matches.value_of("output"), String);
- collect_report(log_paths, PathBuf::from(output_path))
+ let log_paths = collect_matches
+ .values_of_os("logs")
+ .map(|os_values| os_values.map(Path::new).collect())
+ .unwrap_or(Vec::new());
+ let output_path = Path::new(collect_matches.value_of_os("output").unwrap());
+ collect_report(&log_paths, output_path)
} else if let Some(send_matches) = matches.subcommand_matches("send") {
- let report_path = value_t_or_exit!(send_matches.value_of("report"), String);
- let user_email = value_t!(send_matches.value_of("email"), String).unwrap_or(String::new());
- let user_message =
- value_t!(send_matches.value_of("message"), String).unwrap_or(String::new());
- send_problem_report(user_email, user_message, PathBuf::from(report_path))
+ let report_path = Path::new(send_matches.value_of_os("report").unwrap());
+ let user_email = send_matches.value_of("email").unwrap_or("");
+ let user_message = send_matches.value_of("message").unwrap_or("");
+ send_problem_report(user_email, user_message, report_path)
} else {
unreachable!("No sub command given");
}
}
-fn collect_report(log_paths: Vec<PathBuf>, save_path: PathBuf) -> Result<()> {
+fn collect_report(log_paths: &[&Path], output_path: &Path) -> Result<()> {
let mut problem_report = ProblemReport::default();
- for log_path in log_paths.into_iter() {
- problem_report.add_file_log(log_path);
+ for log_path in log_paths {
+ problem_report.add_log(log_path);
}
- write_problem_report(&save_path, problem_report)
- .chain_err(|| ErrorKind::WriteReportError(save_path.clone()))
+ write_problem_report(&output_path, problem_report)
+ .chain_err(|| ErrorKind::WriteReportError(output_path.to_path_buf()))
}
-fn send_problem_report(
- _user_email: String,
- _user_message: String,
- _report_path: PathBuf,
-) -> Result<()> {
- // TODO: Implement submission to master
- Ok(())
+fn send_problem_report(user_email: &str, user_message: &str, report_path: &Path) -> Result<()> {
+ let report_content = read_file_lossy(report_path, REPORT_MAX_SIZE)
+ .chain_err(|| ErrorKind::ReadLogError(report_path.to_path_buf()))?;
+ let mut rpc_client =
+ mullvad_rpc::ProblemReportProxy::connect().chain_err(|| ErrorKind::RpcError)?;
+ rpc_client
+ .problem_report(user_email, user_message, &report_content)
+ .call()
+ .chain_err(|| ErrorKind::RpcError)
}
fn write_problem_report(path: &Path, problem_report: ProblemReport) -> io::Result<()> {
@@ -147,42 +155,14 @@ struct ProblemReport {
}
impl ProblemReport {
- /// Attach file log to this report
- /// Unlike `try_add_file_log` this method uses the error description
- /// instead of log contents if error occurred when reading log file.
- fn add_file_log(&mut self, path: PathBuf) {
- if let Err(e) = self.try_add_file_log(&path)
- .chain_err(|| ErrorKind::ReadLogError(path.clone()))
- {
- self.logs.push((
- path.to_string_lossy().into_owned(),
- e.display_chain().to_string(),
- ));
- }
- }
-
- /// Try reading log from file source and attach it to this report
- fn try_add_file_log(&mut self, path: &Path) -> io::Result<()> {
- Ok(self.logs.push((
- path.to_string_lossy().into_owned(),
- Self::read_log_file(path, LOG_MAX_READ_BYTES)?,
- )))
- }
-
- /// Private helper to safely read the given number of bytes off the tail of UTF-8 log file
- /// and return it as a string
- fn read_log_file(path: &Path, max_bytes: usize) -> io::Result<String> {
- let mut file = File::open(path)?;
- let file_size = file.metadata()?.len();
-
- if file_size > max_bytes as u64 {
- file.seek(SeekFrom::Start(file_size - max_bytes as u64))?;
- }
-
- let capacity = min(file_size, max_bytes as u64) as usize;
- let mut buffer = Vec::with_capacity(capacity);
- file.take(max_bytes as u64).read_to_end(&mut buffer)?;
- Ok(String::from_utf8_lossy(&buffer).into_owned())
+ /// Attach file log to this report. This method uses the error chain instead of log
+ /// contents if error occurred when reading log file.
+ fn add_log(&mut self, path: &Path) {
+ let content = read_file_lossy(path, LOG_MAX_READ_BYTES)
+ .chain_err(|| ErrorKind::ReadLogError(path.to_path_buf()))
+ .unwrap_or_else(|e| e.display_chain().to_string());
+ self.logs
+ .push((path.to_string_lossy().into_owned(), content));
}
}
@@ -198,3 +178,19 @@ impl fmt::Display for ProblemReport {
Ok(())
}
}
+
+/// Helper to lossily read a file to a `String`. If the file size exceeds the given `max_bytes`,
+/// only the last `max_bytes` bytes of the file are read.
+fn read_file_lossy(path: &Path, max_bytes: usize) -> io::Result<String> {
+ let mut file = File::open(path)?;
+ let file_size = file.metadata()?.len();
+
+ if file_size > max_bytes as u64 {
+ file.seek(SeekFrom::Start(file_size - max_bytes as u64))?;
+ }
+
+ let capacity = min(file_size, max_bytes as u64) as usize;
+ let mut buffer = Vec::with_capacity(capacity);
+ file.take(max_bytes as u64).read_to_end(&mut buffer)?;
+ Ok(String::from_utf8_lossy(&buffer).into_owned())
+}
diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs
index e804dcace8..ad2850b926 100644
--- a/mullvad-daemon/src/main.rs
+++ b/mullvad-daemon/src/main.rs
@@ -20,9 +20,6 @@ extern crate serde;
#[macro_use]
extern crate serde_derive;
-#[macro_use]
-extern crate jsonrpc_client_core;
-extern crate jsonrpc_client_http;
extern crate jsonrpc_core;
#[macro_use]
extern crate jsonrpc_macros;
@@ -32,6 +29,7 @@ extern crate jsonrpc_ws_server;
extern crate lazy_static;
extern crate uuid;
+extern crate mullvad_rpc;
extern crate mullvad_types;
extern crate talpid_core;
extern crate talpid_ipc;
@@ -39,7 +37,6 @@ extern crate talpid_types;
mod cli;
mod management_interface;
-mod master;
mod rpc_info;
mod settings;
mod shutdown;
@@ -47,10 +44,9 @@ mod shutdown;
use error_chain::ChainedError;
use futures::Future;
-use jsonrpc_client_http::HttpHandle;
use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender;
use management_interface::{BoxFuture, ManagementInterfaceServer, TunnelCommand};
-use master::AccountsProxy;
+use mullvad_rpc::{AccountsProxy, HttpHandle};
use mullvad_types::account::{AccountData, AccountToken};
use mullvad_types::relay_endpoint::RelayEndpoint;
use mullvad_types::states::{DaemonState, SecurityState, TargetState};
@@ -206,8 +202,7 @@ impl Daemon {
tx,
management_interface_broadcaster,
settings: settings::Settings::load().chain_err(|| "Unable to read settings")?,
- accounts_proxy: master::create_account_proxy()
- .chain_err(|| "Unable to bootstrap RPC client")?,
+ accounts_proxy: AccountsProxy::connect().chain_err(|| "Unable to connect RPC client")?,
firewall: FirewallProxy::new().chain_err(|| ErrorKind::FirewallError)?,
relay_endpoint: None,
tunnel_metadata: None,
@@ -339,7 +334,7 @@ impl Daemon {
fn on_get_account_data(
&mut self,
- tx: OneshotSender<BoxFuture<AccountData, jsonrpc_client_core::Error>>,
+ tx: OneshotSender<BoxFuture<AccountData, mullvad_rpc::Error>>,
account_token: AccountToken,
) {
let rpc_call = self.accounts_proxy
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 829f843fca..43e55f4cb4 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -1,13 +1,13 @@
use error_chain;
use error_chain::ChainedError;
-use jsonrpc_client_core;
use jsonrpc_core::{Error, ErrorCode, Metadata};
use jsonrpc_core::futures::{future, sync, Future};
use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender;
use jsonrpc_macros::pubsub;
use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId};
use jsonrpc_ws_server;
+use mullvad_rpc;
use mullvad_types::account::{AccountData, AccountToken};
use mullvad_types::location::{CountryCode, Location};
use mullvad_types::relay_endpoint::RelayEndpoint;
@@ -126,7 +126,7 @@ pub enum TunnelCommand {
GetState(OneshotSender<DaemonState>),
/// Request the metadata for an account.
GetAccountData(
- OneshotSender<BoxFuture<AccountData, jsonrpc_client_core::Error>>,
+ OneshotSender<BoxFuture<AccountData, mullvad_rpc::Error>>,
AccountToken,
),
/// Set which account token to use for subsequent connection attempts.
@@ -283,9 +283,9 @@ impl<T: From<TunnelCommand> + 'static + Send> ManagementInterface<T> {
/// Converts the given error to an error that can be given to the caller of the API.
/// Will let any actual RPC error through as is, any other error is changed to an internal
/// error.
- fn map_rpc_error(error: jsonrpc_client_core::Error) -> Error {
+ fn map_rpc_error(error: mullvad_rpc::Error) -> Error {
match error.kind() {
- &jsonrpc_client_core::ErrorKind::JsonRpcError(ref rpc_error) => {
+ &mullvad_rpc::ErrorKind::JsonRpcError(ref rpc_error) => {
// We have to manually copy the error since we have different
// versions of the jsonrpc_core library at the moment.
Error {
@@ -344,7 +344,7 @@ impl<T: From<TunnelCommand> + 'static + Send> ManagementInterfaceApi for Managem
let future = self.send_command_to_daemon(TunnelCommand::GetAccountData(tx, account_token))
.and_then(|_| rx.map_err(|_| Error::internal_error()))
.and_then(|rpc_future| {
- rpc_future.map_err(|error: jsonrpc_client_core::Error| {
+ rpc_future.map_err(|error: mullvad_rpc::Error| {
error!(
"Unable to get account data from master: {}",
error.display_chain()
diff --git a/mullvad-daemon/src/master.rs b/mullvad-daemon/src/master.rs
deleted file mode 100644
index 37bfbe65e5..0000000000
--- a/mullvad-daemon/src/master.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use chrono::DateTime;
-use chrono::offset::Utc;
-use jsonrpc_client_http::{Error as HttpError, HttpHandle, HttpTransport};
-
-use mullvad_types::account::AccountToken;
-
-static MASTER_API_URI: &str = "https://api.mullvad.net/rpc/";
-
-pub fn create_account_proxy() -> Result<AccountsProxy<HttpHandle>, HttpError> {
- let transport = HttpTransport::new()?.handle(MASTER_API_URI)?;
- Ok(AccountsProxy::new(transport))
-}
-
-jsonrpc_client!(pub struct AccountsProxy {
- pub fn get_expiry(&mut self, account_token: AccountToken) -> RpcRequest<DateTime<Utc>>;
-});
diff --git a/mullvad-rpc/Cargo.toml b/mullvad-rpc/Cargo.toml
new file mode 100644
index 0000000000..41f7fccb2d
--- /dev/null
+++ b/mullvad-rpc/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "mullvad-rpc"
+version = "0.1.0"
+authors = ["Mullvad VPN <admin@mullvad.net>", "Linus Färnstrand <linus@mullvad.net>", "Erik Larkö <erik@mullvad.net>", "Andrej Mihajlov <and@mullvad.net>"]
+description = "Mullvad VPN RPC clients. Providing an interface to query our infrastructure for information."
+license = "GPL-3.0"
+
+[dependencies]
+chrono = { version = "0.4", features = ["serde"] }
+jsonrpc-client-core = "0.2.1"
+jsonrpc-client-http = "0.2.1"
+
+mullvad-types = { path = "../mullvad-types" }
diff --git a/mullvad-rpc/src/lib.rs b/mullvad-rpc/src/lib.rs
new file mode 100644
index 0000000000..9174f1e684
--- /dev/null
+++ b/mullvad-rpc/src/lib.rs
@@ -0,0 +1,49 @@
+//! # License
+//!
+//! Copyright (C) 2017 Amagicom AB
+//!
+//! This program is free software: you can redistribute it and/or modify it under the terms of the
+//! GNU General Public License as published by the Free Software Foundation, either version 3 of
+//! the License, or (at your option) any later version.
+
+extern crate chrono;
+#[macro_use]
+extern crate jsonrpc_client_core;
+extern crate jsonrpc_client_http;
+
+extern crate mullvad_types;
+
+use chrono::DateTime;
+use chrono::offset::Utc;
+use jsonrpc_client_http::HttpTransport;
+
+pub use jsonrpc_client_core::{Error, ErrorKind};
+pub use jsonrpc_client_http::{Error as HttpError, HttpHandle};
+
+use mullvad_types::account::AccountToken;
+
+
+static MASTER_API_URI: &str = "https://api.mullvad.net/rpc/";
+
+
+jsonrpc_client!(pub struct AccountsProxy {
+ pub fn get_expiry(&mut self, account_token: AccountToken) -> RpcRequest<DateTime<Utc>>;
+});
+
+impl AccountsProxy<HttpHandle> {
+ pub fn connect() -> Result<Self, HttpError> {
+ let transport = HttpTransport::new()?.handle(MASTER_API_URI)?;
+ Ok(AccountsProxy::new(transport))
+ }
+}
+
+jsonrpc_client!(pub struct ProblemReportProxy {
+ pub fn problem_report(&mut self, email: &str, message: &str, log: &str) -> RpcRequest<()>;
+});
+
+impl ProblemReportProxy<HttpHandle> {
+ pub fn connect() -> Result<Self, HttpError> {
+ let transport = HttpTransport::new()?.handle(MASTER_API_URI)?;
+ Ok(ProblemReportProxy::new(transport))
+ }
+}