summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls <emils@mullvad.net>2020-03-16 13:15:59 +0000
committerEmīls Piņķis <emils@mullvad.net>2020-04-27 11:17:00 +0100
commit738b59f3cea4b7f99e9dfef23c61a2aa1cda9559 (patch)
tree35a4f1eda6c7982765e781fe3c2fb35096d4e297
parentb8bd0ec937b92d960a539c6a1c6b51a03865afce (diff)
downloadmullvadvpn-738b59f3cea4b7f99e9dfef23c61a2aa1cda9559.tar.xz
mullvadvpn-738b59f3cea4b7f99e9dfef23c61a2aa1cda9559.zip
Use HTTP RPCs in daemon
-rw-r--r--mullvad-daemon/src/account_history.rs12
-rw-r--r--mullvad-daemon/src/event_loop.rs38
-rw-r--r--mullvad-daemon/src/geoip.rs88
-rw-r--r--mullvad-daemon/src/lib.rs92
-rw-r--r--mullvad-daemon/src/management_interface.rs60
-rw-r--r--mullvad-daemon/src/relays.rs14
-rw-r--r--mullvad-daemon/src/version_check.rs13
-rw-r--r--mullvad-daemon/src/wireguard.rs64
8 files changed, 219 insertions, 162 deletions
diff --git a/mullvad-daemon/src/account_history.rs b/mullvad-daemon/src/account_history.rs
index ea8f23757a..56ebc6dc17 100644
--- a/mullvad-daemon/src/account_history.rs
+++ b/mullvad-daemon/src/account_history.rs
@@ -5,7 +5,7 @@ use futures::{
future::{self, Executor, Future},
sync::oneshot,
};
-use mullvad_rpc::{HttpHandle, WireguardKeyProxy};
+use mullvad_rpc::{rest::MullvadRestHandle, WireguardKeyProxy};
use mullvad_types::{account::AccountToken, wireguard::WireguardData};
use std::{
collections::VecDeque,
@@ -38,7 +38,7 @@ static ACCOUNT_HISTORY_LIMIT: usize = 3;
pub struct AccountHistory {
file: io::BufWriter<fs::File>,
accounts: VecDeque<AccountEntry>,
- rpc_handle: HttpHandle,
+ rpc_handle: MullvadRestHandle,
tokio_remote: Remote,
}
@@ -46,7 +46,7 @@ pub struct AccountHistory {
impl AccountHistory {
pub fn new(
cache_dir: &Path,
- rpc_handle: HttpHandle,
+ rpc_handle: MullvadRestHandle,
tokio_remote: Remote,
) -> Result<AccountHistory> {
let mut options = fs::OpenOptions::new();
@@ -152,8 +152,7 @@ impl AccountHistory {
wg_data: &WireguardData,
) -> impl Future<Item = (), Error = ()> {
let mut rpc = WireguardKeyProxy::new(self.rpc_handle.clone());
- rpc.remove_wg_key(String::from(account), wg_data.private_key.public_key())
- .map(|removed| log::debug!("Key existed on account: {}", removed))
+ rpc.remove_wireguard_key(String::from(account), &wg_data.private_key.public_key())
.map_err(|e| log::error!("Failed to remove WireGuard key: {}", e))
}
@@ -216,8 +215,7 @@ impl AccountHistory {
for entry in self.accounts.iter() {
if let Some(wg_data) = &entry.wireguard {
let fut = rpc
- .remove_wg_key(entry.account.clone(), wg_data.private_key.public_key())
- .map(|_| ())
+ .remove_wireguard_key(entry.account.clone(), &wg_data.private_key.public_key())
.map_err(|e| log::error!("Failed to remove WireGuard key: {}", e));
removal_futures.push(fut);
}
diff --git a/mullvad-daemon/src/event_loop.rs b/mullvad-daemon/src/event_loop.rs
new file mode 100644
index 0000000000..238b9f4eef
--- /dev/null
+++ b/mullvad-daemon/src/event_loop.rs
@@ -0,0 +1,38 @@
+use futures::{sync::oneshot, Future};
+use std::thread;
+use tokio_core::reactor::{Core, Remote};
+
+pub struct CoreHandle {
+ /// Remote used to spawn futures on the daemon's event loop.
+ pub remote: Remote,
+ /// A sender that will cause the event loop to stop once it's dropped.
+ shutdown_tx: Option<oneshot::Sender<()>>,
+}
+
+impl Drop for CoreHandle {
+ fn drop(&mut self) {
+ if let Some(shutdown_tx) = self.shutdown_tx.take() {
+ if shutdown_tx.send(()).is_err() {
+ log::error!("Core already shut down");
+ }
+ }
+ }
+}
+
+/// Panics if a new tokio event loop can't be spawned.
+pub fn spawn() -> CoreHandle {
+ let (tx, rx) = oneshot::channel();
+ let (shutdown_tx, shutdown_rx) = oneshot::channel();
+ thread::spawn(move || {
+ let mut core = Core::new().expect("Failed to spawn event loop");
+ let remote = core.remote();
+ let _ = tx.send(remote);
+ let _ = core.run(shutdown_rx);
+ });
+ let remote = rx.wait().expect("Failed to spawn event loop");
+
+ CoreHandle {
+ remote,
+ shutdown_tx: Some(shutdown_tx),
+ }
+}
diff --git a/mullvad-daemon/src/geoip.rs b/mullvad-daemon/src/geoip.rs
index 5be502f0a9..5cc3085bfe 100644
--- a/mullvad-daemon/src/geoip.rs
+++ b/mullvad-daemon/src/geoip.rs
@@ -1,69 +1,53 @@
use futures::{self, Future};
-use mullvad_rpc;
+use mullvad_rpc::{self, rest::RequestServiceHandle};
use mullvad_types::location::{AmIMullvad, GeoIpLocation};
-use serde_json;
const URI_V4: &str = "https://ipv4.am.i.mullvad.net/json";
const URI_V6: &str = "https://ipv6.am.i.mullvad.net/json";
-#[derive(err_derive::Error, Debug)]
-pub enum Error {
- /// Unable to send request to HTTP client.
- #[error(display = "Unable to send GeoIP request to HTTP client")]
- SendRequestError,
-
- /// The request was dropped without any response
- #[error(display = "The GeoIP request was dropped without any response")]
- NoResponse,
-
- /// Error in the HTTP client when requesting GeoIP
- #[error(display = "Failed to request GeoIP")]
- Transport(#[error(source)] mullvad_rpc::rest::Error),
-
- /// Failed to deserialize GeoIP response
- #[error(display = "Failed to deserialize GeoIP response")]
- Deserialize(#[error(source)] serde_json::error::Error),
-}
-
-
pub fn send_location_request(
- request_sender: mullvad_rpc::rest::RequestSender,
-) -> impl Future<Item = GeoIpLocation, Error = Error> {
+ request_sender: RequestServiceHandle,
+) -> impl Future<Item = GeoIpLocation, Error = mullvad_rpc::rest::Error> {
let v4_future =
send_location_request_internal(URI_V4, request_sender.clone()).map(GeoIpLocation::from);
let v6_future = send_location_request_internal(URI_V6, request_sender).map(GeoIpLocation::from);
- v4_future.then(|v4_result| {
- v6_future.then(|v6_result| match (v4_result, v6_result) {
- (Ok(mut v4), Ok(v6)) => {
- v4.ipv6 = v6.ipv6;
- v4.mullvad_exit_ip = v4.mullvad_exit_ip && v6.mullvad_exit_ip;
- Ok(v4)
- }
- (Ok(v4), Err(e)) => {
- log::debug!("Unable to fetch IPv6 GeoIP location: {}", e);
- Ok(v4)
- }
- (Err(e), Ok(v6)) => {
- log::debug!("Unable to fetch IPv4 GeoIP location: {}", e);
- Ok(v6)
- }
- (Err(e_v4), Err(_)) => Err(e_v4),
- })
- })
+ v4_future.then(
+ |v4_result: Result<GeoIpLocation, mullvad_rpc::rest::Error>| {
+ v6_future.then(
+ |v6_result: Result<GeoIpLocation, mullvad_rpc::rest::Error>| match (
+ v4_result, v6_result,
+ ) {
+ (Ok(mut v4), Ok(v6)) => {
+ v4.ipv6 = v6.ipv6;
+ v4.mullvad_exit_ip = v4.mullvad_exit_ip && v6.mullvad_exit_ip;
+ Ok(v4)
+ }
+ (Ok(v4), Err(e)) => {
+ log::debug!("Unable to fetch IPv6 GeoIP location: {}", e);
+ Ok(v4)
+ }
+ (Err(e), Ok(v6)) => {
+ log::debug!("Unable to fetch IPv4 GeoIP location: {}", e);
+ Ok(v6)
+ }
+ (Err(e_v4), Err(_)) => Err(e_v4),
+ },
+ )
+ },
+ )
}
fn send_location_request_internal(
uri: &'static str,
- request_sender: mullvad_rpc::rest::RequestSender,
-) -> impl Future<Item = AmIMullvad, Error = Error> {
- let (response_tx, response_rx) = futures::sync::oneshot::channel();
- let request = mullvad_rpc::rest::create_get_request(uri.parse().unwrap());
-
- futures::Sink::send(request_sender, (request, response_tx))
- .map_err(|_| Error::SendRequestError)
- .and_then(|_| response_rx.map_err(|_| Error::NoResponse))
- .and_then(|response_result| response_result.map_err(Error::Transport))
- .and_then(|response| serde_json::from_slice(&response).map_err(Error::Deserialize))
+ service: RequestServiceHandle,
+) -> impl Future<Item = AmIMullvad, Error = mullvad_rpc::rest::Error> {
+ let future_service = service.clone();
+ let future = async move {
+ let request = mullvad_rpc::rest::RestRequest::get(uri)?;
+ let response = future_service.request(request).await?;
+ mullvad_rpc::rest::deserialize_body(response).await
+ };
+ service.compat_spawn(future)
}
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 6dd6812dd2..4f8d828d37 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -27,7 +27,7 @@ use futures::{
Future, Stream,
};
use log::{debug, error, info, warn};
-use mullvad_rpc::{AccountsProxy, HttpHandle, WireguardKeyProxy};
+use mullvad_rpc::AccountsProxy;
use mullvad_types::{
account::{AccountData, AccountToken, VoucherSubmission},
endpoint::MullvadEndpoint,
@@ -71,6 +71,7 @@ use talpid_types::{
mod wireguard;
const TARGET_START_STATE_FILE: &str = "target-start-state.json";
+mod event_loop;
/// FIXME(linus): This is here just because the futures crate has deprecated it and jsonrpc_core
/// did not introduce their own yet (https://github.com/paritytech/jsonrpc/pull/196).
@@ -89,10 +90,7 @@ pub enum Error {
InitIoEventLoop(#[error(source)] io::Error),
#[error(display = "Unable to create RPC client")]
- InitRpcClient(#[error(source)] mullvad_rpc::HttpError),
-
- #[error(display = "Unable to create am.i.mullvad client")]
- InitHttpsClient(#[error(source)] mullvad_rpc::rest::Error),
+ InitRpcFactory(#[error(source)] mullvad_rpc::Error),
#[error(display = "Unable to load account history with wireguard key cache")]
LoadAccountHistory(#[error(source)] account_history::Error),
@@ -147,17 +145,17 @@ pub enum DaemonCommand {
GetState(oneshot::Sender<TunnelState>),
/// Get the current geographical location.
GetCurrentLocation(oneshot::Sender<Option<GeoIpLocation>>),
- CreateNewAccount(oneshot::Sender<std::result::Result<String, mullvad_rpc::Error>>),
+ CreateNewAccount(oneshot::Sender<std::result::Result<String, mullvad_rpc::rest::Error>>),
/// Request the metadata for an account.
GetAccountData(
- oneshot::Sender<BoxFuture<AccountData, mullvad_rpc::Error>>,
+ oneshot::Sender<BoxFuture<AccountData, mullvad_rpc::rest::Error>>,
AccountToken,
),
/// Request www auth token for an account
- GetWwwAuthToken(oneshot::Sender<BoxFuture<String, mullvad_rpc::Error>>),
+ GetWwwAuthToken(oneshot::Sender<BoxFuture<String, mullvad_rpc::rest::Error>>),
/// Submit voucher to add time to the current account. Returns time added in seconds
SubmitVoucher(
- oneshot::Sender<BoxFuture<VoucherSubmission, mullvad_rpc::Error>>,
+ oneshot::Sender<BoxFuture<VoucherSubmission, mullvad_rpc::rest::Error>>,
String,
),
/// Request account history
@@ -244,7 +242,7 @@ pub(crate) enum InternalDaemonEvent {
/// New Account created
NewAccountEvent(
AccountToken,
- oneshot::Sender<Result<String, mullvad_rpc::Error>>,
+ oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>,
),
/// The background job fetching new `AppVersionInfo`s got a new info object.
NewAppVersionInfo(AppVersionInfo),
@@ -439,11 +437,10 @@ pub struct Daemon<L: EventListener> {
event_listener: L,
settings: SettingsPersister,
account_history: account_history::AccountHistory,
- wg_key_proxy: WireguardKeyProxy<HttpHandle>,
- accounts_proxy: AccountsProxy<HttpHandle>,
- https_handle: mullvad_rpc::rest::RequestSender,
+ accounts_proxy: AccountsProxy,
+ rpc_runtime: mullvad_rpc::MullvadRpcRuntime,
wireguard_key_manager: wireguard::KeyManager,
- tokio_remote: tokio_core::reactor::Remote,
+ core_handle: event_loop::CoreHandle,
relay_selector: relays::RelaySelector,
last_generated_relay: Option<Relay>,
last_generated_bridge_relay: Option<Relay>,
@@ -471,20 +468,11 @@ where
let (tunnel_state_machine_shutdown_tx, tunnel_state_machine_shutdown_signal) =
oneshot::channel();
- let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::with_cache_dir(&cache_dir, &ca_path);
-
- let (rpc_handle, https_handle, tokio_remote) =
- mullvad_rpc::event_loop::create(move |core| {
- let handle = core.handle();
- let rpc = rpc_manager.new_connection_on_event_loop(&handle);
- let https_handle = mullvad_rpc::rest::create_https_client(&ca_path, &handle);
- let remote = core.remote();
- (rpc, https_handle, remote)
- })
- .map_err(Error::InitIoEventLoop)?;
+ let mut rpc_runtime = mullvad_rpc::MullvadRpcRuntime::with_cache_dir(&cache_dir, &ca_path)
+ .map_err(Error::InitRpcFactory)?;
+ let rpc_handle = rpc_runtime.mullvad_rest_handle();
- let rpc_handle = rpc_handle.map_err(Error::InitRpcClient)?;
- let https_handle = https_handle.map_err(Error::InitHttpsClient)?;
+ let core_handle = event_loop::spawn();
let relay_list_listener = event_listener.clone();
let on_relay_list_update = move |relay_list: &RelayList| {
@@ -506,7 +494,7 @@ where
internal_event_tx.to_specialized_sender(),
app_version_info.clone(),
);
- tokio_remote.spawn(|_| version_check_future);
+ core_handle.remote.spawn(|_| version_check_future);
let mut settings = SettingsPersister::load(&settings_dir);
@@ -517,7 +505,7 @@ where
let account_history = account_history::AccountHistory::new(
&cache_dir,
rpc_handle.clone(),
- tokio_remote.clone(),
+ core_handle.remote.clone(),
)
.map_err(Error::LoadAccountHistory)?;
@@ -561,7 +549,7 @@ where
let wireguard_key_manager = wireguard::KeyManager::new(
internal_event_tx.clone(),
rpc_handle.clone(),
- tokio_remote.clone(),
+ core_handle.remote.clone(),
);
// Attempt to download a fresh relay list
@@ -591,11 +579,10 @@ where
event_listener,
settings,
account_history,
- wg_key_proxy: WireguardKeyProxy::new(rpc_handle.clone()),
+ rpc_runtime,
accounts_proxy: AccountsProxy::new(rpc_handle),
- https_handle,
wireguard_key_manager,
- tokio_remote,
+ core_handle,
relay_selector,
last_generated_relay: None,
last_generated_bridge_relay: None,
@@ -1063,7 +1050,7 @@ where
fn handle_new_account_event(
&mut self,
new_token: AccountToken,
- tx: oneshot::Sender<Result<String, mullvad_rpc::Error>>,
+ tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>,
) {
match self.set_account(Some(new_token.clone())) {
Ok(_) => {
@@ -1106,7 +1093,7 @@ where
Self::oneshot_send(tx, self.tunnel_state.clone(), "current state");
}
- fn on_get_current_location(&self, tx: oneshot::Sender<Option<GeoIpLocation>>) {
+ fn on_get_current_location(&mut self, tx: oneshot::Sender<Option<GeoIpLocation>>) {
use self::TunnelState::*;
let get_location: Box<dyn Future<Item = Option<GeoIpLocation>, Error = ()> + Send> =
match &self.tunnel_state {
@@ -1131,13 +1118,13 @@ where
}
};
- self.tokio_remote.spawn(move |_| {
+ self.core_handle.remote.spawn(move |_| {
get_location.map(|location| Self::oneshot_send(tx, location, "current location"))
});
}
- fn get_geo_location(&self) -> impl Future<Item = GeoIpLocation, Error = ()> {
- let https_handle = self.https_handle.clone();
+ fn get_geo_location(&mut self) -> impl Future<Item = GeoIpLocation, Error = ()> {
+ let https_handle = self.rpc_runtime.rest_handle();
geoip::send_location_request(https_handle).map_err(|e| {
warn!("Unable to fetch GeoIP location: {}", e.display_chain());
@@ -1166,7 +1153,10 @@ where
})
}
- fn on_create_new_account(&mut self, tx: oneshot::Sender<Result<String, mullvad_rpc::Error>>) {
+ fn on_create_new_account(
+ &mut self,
+ tx: oneshot::Sender<Result<String, mullvad_rpc::rest::Error>>,
+ ) {
let daemon_tx = self.tx.clone();
let future = self
.accounts_proxy
@@ -1184,14 +1174,14 @@ where
Ok(())
});
- if self.tokio_remote.execute(future).is_err() {
+ if self.core_handle.remote.execute(future).is_err() {
log::error!("Failed to spawn future for creating a new account");
}
}
fn on_get_account_data(
&mut self,
- tx: oneshot::Sender<BoxFuture<AccountData, mullvad_rpc::Error>>,
+ tx: oneshot::Sender<BoxFuture<AccountData, mullvad_rpc::rest::Error>>,
account_token: AccountToken,
) {
let rpc_call = self
@@ -1203,7 +1193,7 @@ where
fn on_get_www_auth_token(
&mut self,
- tx: oneshot::Sender<BoxFuture<String, mullvad_rpc::Error>>,
+ tx: oneshot::Sender<BoxFuture<String, mullvad_rpc::rest::Error>>,
) {
if let Some(account_token) = self.settings.get_account_token() {
let rpc_call = self.accounts_proxy.get_www_auth_token(account_token);
@@ -1213,7 +1203,7 @@ where
fn on_submit_voucher(
&mut self,
- tx: oneshot::Sender<BoxFuture<VoucherSubmission, mullvad_rpc::Error>>,
+ tx: oneshot::Sender<BoxFuture<VoucherSubmission, mullvad_rpc::rest::Error>>,
voucher: String,
) {
if let Some(account_token) = self.settings.get_account_token() {
@@ -1647,7 +1637,10 @@ where
Ok(keygen_event)
}
Err(wireguard::Error::TooManyKeys) => Ok(KeygenEvent::TooManyKeys),
- Err(e) => Err(format!("Failed to generate new key - {}", e)),
+ Err(e) => Err(format!(
+ "Failed to generate new key - {}",
+ e.display_chain_with_msg("Failed to generate new wireguard key:")
+ )),
}
};
@@ -1698,13 +1691,14 @@ where
};
let fut = self
- .wg_key_proxy
- .check_wg_key(account, public_key)
- .map(|is_valid| {
+ .wireguard_key_manager
+ .verify_wireguard_key(account, public_key)
+ .and_then(|is_valid| {
Self::oneshot_send(tx, is_valid, "verify_wireguard_key response");
+ Ok(())
})
- .map_err(|e| log::error!("Failed to verify wireguard key - {}", e));
- if let Err(e) = self.tokio_remote.execute(fut) {
+ .map_err(|e: wireguard::Error| log::error!("Failed to verify wireguard key - {}", e));
+ if let Err(e) = self.core_handle.remote.execute(fut) {
log::error!("Failed to spawn a future to verify wireguard key: {:?}", e);
}
}
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 00254472be..84c5db8570 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -7,7 +7,7 @@ use jsonrpc_ipc_server;
use jsonrpc_macros::{build_rpc_trait, metadata, pubsub};
use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId};
use mullvad_paths;
-use mullvad_rpc;
+use mullvad_rpc::{rest::Error as RestError, StatusCode};
use mullvad_types::{
account::{AccountData, AccountToken, VoucherSubmission},
location::GeoIpLocation,
@@ -26,6 +26,11 @@ use talpid_ipc;
use talpid_types::ErrorExt;
use uuid;
+pub const INVALID_VOUCHER_CODE: i64 = -400;
+pub const VOUCHER_USED_ALREADY_CODE: i64 = -401;
+pub const INVALID_ACCOUNT_CODE: i64 = -200;
+
+
build_rpc_trait! {
pub trait ManagementInterfaceApi {
type Metadata;
@@ -306,18 +311,16 @@ impl ManagementInterface {
future::result(self.tx.send(command)).map_err(|_| Error::internal_error())
}
- /// 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: &mullvad_rpc::Error) -> Error {
- match error.kind() {
- 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.
+ /// Converts a REST API error for an account into a JSONRPC error for the JSONRPC client.
+ fn map_rest_account_error(error: RestError) -> Error {
+ match error {
+ RestError::ApiError(status, message)
+ if status == StatusCode::UNAUTHORIZED || status == StatusCode::FORBIDDEN =>
+ {
Error {
- code: ErrorCode::from(rpc_error.code.code()),
- message: rpc_error.message.clone(),
- data: rpc_error.data.clone(),
+ code: ErrorCode::from(INVALID_ACCOUNT_CODE),
+ message,
+ data: None,
}
}
_ => Error::internal_error(),
@@ -335,7 +338,7 @@ impl ManagementInterfaceApi for ManagementInterface {
.and_then(|_| rx.map_err(|_| Error::internal_error()))
.and_then(|result| match result {
Ok(account_token) => Ok(account_token),
- Err(e) => Err(Self::map_rpc_error(&e)),
+ Err(_) => Err(Error::internal_error()),
});
Box::new(future)
@@ -352,12 +355,12 @@ impl ManagementInterfaceApi for ManagementInterface {
.send_command_to_daemon(DaemonCommand::GetAccountData(tx, account_token))
.and_then(|_| rx.map_err(|_| Error::internal_error()))
.and_then(|rpc_future| {
- rpc_future.map_err(|error: mullvad_rpc::Error| {
+ rpc_future.map_err(|error: RestError| {
log::error!(
"Unable to get account data from API: {}",
error.display_chain()
);
- Self::map_rpc_error(&error)
+ Self::map_rest_account_error(error)
})
});
Box::new(future)
@@ -370,12 +373,12 @@ impl ManagementInterfaceApi for ManagementInterface {
.send_command_to_daemon(DaemonCommand::GetWwwAuthToken(tx))
.and_then(|_| rx.map_err(|_| Error::internal_error()))
.and_then(|rpc_future| {
- rpc_future.map_err(|error: mullvad_rpc::Error| {
+ rpc_future.map_err(|error: mullvad_rpc::rest::Error| {
log::error!(
"Unable to get account data from API: {}",
error.display_chain()
);
- Self::map_rpc_error(&error)
+ Self::map_rest_account_error(error)
})
});
Box::new(future)
@@ -391,7 +394,28 @@ impl ManagementInterfaceApi for ManagementInterface {
let future = self
.send_command_to_daemon(DaemonCommand::SubmitVoucher(tx, voucher))
.and_then(|_| rx.map_err(|_| Error::internal_error()))
- .and_then(|f| f.map_err(|e| Self::map_rpc_error(&e)));
+ .and_then(|f| {
+ f.map_err(|e| match e {
+ RestError::ApiError(StatusCode::BAD_REQUEST, message) => {
+ match &message.as_str() {
+ &mullvad_rpc::INVALID_VOUCHER => Error {
+ code: ErrorCode::from(INVALID_VOUCHER_CODE),
+ message,
+ data: None,
+ },
+
+ &mullvad_rpc::VOUCHER_USED => Error {
+ code: ErrorCode::from(VOUCHER_USED_ALREADY_CODE),
+ message,
+ data: None,
+ },
+
+ _ => Error::internal_error(),
+ }
+ }
+ _ => Error::internal_error(),
+ })
+ });
Box::new(future)
}
diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs
index 25a3b8eb40..94e6c66cf9 100644
--- a/mullvad-daemon/src/relays.rs
+++ b/mullvad-daemon/src/relays.rs
@@ -3,7 +3,7 @@
use chrono::{DateTime, Local};
use futures::Future;
-use mullvad_rpc::{HttpHandle, RelayListProxy};
+use mullvad_rpc::{rest::MullvadRestHandle, RelayListProxy};
use mullvad_types::{
endpoint::MullvadEndpoint,
location::Location,
@@ -52,7 +52,7 @@ pub enum Error {
WriteRelayCache(#[error(source)] io::Error),
#[error(display = "Failed to download the list of relays")]
- Download(#[error(source)] mullvad_rpc::Error),
+ Download(#[error(source)] mullvad_rpc::rest::Error),
#[error(display = "Timed out when trying to download the list of relays")]
DownloadTimeout,
@@ -155,7 +155,7 @@ impl RelaySelector {
/// Returns a new `RelaySelector` backed by relays cached on disk. Use the `update` method
/// to refresh the relay list from the internet.
pub fn new(
- rpc_handle: HttpHandle,
+ rpc_handle: MullvadRestHandle,
on_update: impl Fn(&RelayList) + Send + 'static,
resource_dir: &Path,
cache_dir: &Path,
@@ -783,7 +783,7 @@ impl RelaySelector {
type RelayListUpdaterHandle = mpsc::Sender<()>;
struct RelayListUpdater {
- rpc_client: RelayListProxy<HttpHandle>,
+ rpc_client: RelayListProxy,
cache_path: PathBuf,
parsed_relays: Arc<Mutex<ParsedRelays>>,
on_update: Box<dyn Fn(&RelayList)>,
@@ -792,7 +792,7 @@ struct RelayListUpdater {
impl RelayListUpdater {
pub fn spawn(
- rpc_handle: HttpHandle,
+ rpc_handle: MullvadRestHandle,
cache_path: PathBuf,
parsed_relays: Arc<Mutex<ParsedRelays>>,
on_update: Box<dyn Fn(&RelayList) + Send + 'static>,
@@ -807,7 +807,7 @@ impl RelayListUpdater {
}
fn new(
- rpc_handle: HttpHandle,
+ rpc_handle: MullvadRestHandle,
cache_path: PathBuf,
parsed_relays: Arc<Mutex<ParsedRelays>>,
on_update: Box<dyn Fn(&RelayList)>,
@@ -879,7 +879,7 @@ impl RelayListUpdater {
}
fn download_relay_list(&mut self) -> Result<RelayList, Error> {
- let download_future = self.rpc_client.relay_list_v3().map_err(Error::Download);
+ let download_future = self.rpc_client.relay_list().map_err(Error::Download);
let relay_list = Timer::default()
.timeout(download_future, DOWNLOAD_TIMEOUT)
.wait()?;
diff --git a/mullvad-daemon/src/version_check.rs b/mullvad-daemon/src/version_check.rs
index 754509b407..7a4446708d 100644
--- a/mullvad-daemon/src/version_check.rs
+++ b/mullvad-daemon/src/version_check.rs
@@ -1,6 +1,6 @@
use crate::{version::PRODUCT_VERSION, DaemonEventSender};
use futures::{Async, Future, Poll};
-use mullvad_rpc::{AppVersionProxy, HttpHandle};
+use mullvad_rpc::{rest::MullvadRestHandle, AppVersionProxy};
use mullvad_types::version::AppVersionInfo;
use serde::{Deserialize, Serialize};
use std::{
@@ -68,7 +68,7 @@ pub enum Error {
DownloadTimeout,
#[error(display = "Failed to check the latest app version")]
- Download(#[error(source)] mullvad_rpc::Error),
+ Download(#[error(source)] mullvad_rpc::rest::Error),
#[error(display = "Clearing version check cache due to a version mismatch")]
CacheVersionMismatch,
@@ -82,7 +82,7 @@ impl<T> From<TimeoutError<T>> for Error {
pub(crate) struct VersionUpdater {
- version_proxy: AppVersionProxy<HttpHandle>,
+ version_proxy: AppVersionProxy,
cache_path: PathBuf,
update_sender: DaemonEventSender<AppVersionInfo>,
last_app_version_info: AppVersionInfo,
@@ -97,7 +97,7 @@ enum VersionUpdaterState {
impl VersionUpdater {
pub fn new(
- rpc_handle: HttpHandle,
+ rpc_handle: MullvadRestHandle,
cache_dir: PathBuf,
update_sender: DaemonEventSender<AppVersionInfo>,
last_app_version_info: AppVersionInfo,
@@ -123,7 +123,7 @@ impl VersionUpdater {
) -> Box<dyn Future<Item = AppVersionInfo, Error = Error> + Send + 'static> {
let download_future = self
.version_proxy
- .app_version_check(&PRODUCT_VERSION.to_owned(), PLATFORM)
+ .version_check(PRODUCT_VERSION.to_owned(), PLATFORM)
.map_err(Error::Download);
let future = Timer::default().timeout(download_future, DOWNLOAD_TIMEOUT);
Box::new(future)
@@ -226,8 +226,9 @@ pub fn load_cache(cache_dir: &Path) -> AppVersionInfo {
);
// If we don't have a cache, start out with sane defaults.
AppVersionInfo {
- current_is_supported: true,
+ supported: true,
latest_stable: PRODUCT_VERSION.to_owned(),
+ latest_beta: PRODUCT_VERSION.to_owned(),
latest: PRODUCT_VERSION.to_owned(),
}
}
diff --git a/mullvad-daemon/src/wireguard.rs b/mullvad-daemon/src/wireguard.rs
index 9b234dfaab..5cc4b9be7d 100644
--- a/mullvad-daemon/src/wireguard.rs
+++ b/mullvad-daemon/src/wireguard.rs
@@ -1,7 +1,7 @@
use crate::{account_history::AccountHistory, DaemonEventSender, InternalDaemonEvent};
use chrono::offset::Utc;
use futures::{future::Executor, stream::Stream, sync::oneshot, Async, Future, Poll};
-use jsonrpc_client_core::Error as JsonRpcError;
+use mullvad_rpc::rest::{Error as RestError, MullvadRestHandle};
use mullvad_types::account::AccountToken;
pub use mullvad_types::wireguard::*;
use std::time::Duration;
@@ -17,8 +17,6 @@ use tokio_retry::{
};
use tokio_timer;
-const TOO_MANY_KEYS_ERROR_CODE: i64 = -703;
-
/// Default automatic key rotation
const DEFAULT_AUTOMATIC_KEY_ROTATION: Duration = Duration::from_secs(7 * 24 * 60 * 60);
/// How long to wait before reattempting to rotate keys on failure
@@ -31,8 +29,8 @@ const KEY_CHECK_INTERVAL: Duration = Duration::from_secs(60);
pub enum Error {
#[error(display = "Failed to spawn future")]
ExectuionError,
- #[error(display = "Unexpected RPC error")]
- RpcError(#[error(source)] jsonrpc_client_core::Error),
+ #[error(display = "Unexpected HTTP request error")]
+ RestError(#[error(source)] mullvad_rpc::rest::Error),
#[error(display = "Account already has maximum number of keys")]
TooManyKeys,
#[error(display = "Failed to create rotation timer")]
@@ -43,7 +41,7 @@ pub type Result<T> = std::result::Result<T, Error>;
pub struct KeyManager {
daemon_tx: DaemonEventSender,
- http_handle: mullvad_rpc::HttpHandle,
+ http_handle: MullvadRestHandle,
tokio_remote: Remote,
current_job: Option<CancelHandle>,
@@ -54,7 +52,7 @@ pub struct KeyManager {
impl KeyManager {
pub(crate) fn new(
daemon_tx: DaemonEventSender,
- http_handle: mullvad_rpc::HttpHandle,
+ http_handle: MullvadRestHandle,
tokio_remote: Remote,
) -> Self {
Self {
@@ -149,6 +147,25 @@ impl KeyManager {
))
}
+ /// Verifies whether a key is valid or not.
+ pub fn verify_wireguard_key(
+ &self,
+ account: AccountToken,
+ key: talpid_types::net::wireguard::PublicKey,
+ ) -> impl Future<Item = bool, Error = Error> {
+ let mut rpc = mullvad_rpc::WireguardKeyProxy::new(self.http_handle.clone());
+ rpc.get_wireguard_key(account, &key)
+ .then(|response| match response {
+ Ok(_) => Ok(true),
+ Err(mullvad_rpc::rest::Error::ApiError(status, _code))
+ if status == mullvad_rpc::StatusCode::NOT_FOUND =>
+ {
+ Ok(false)
+ }
+ Err(err) => Err(Self::map_rpc_error(err)),
+ })
+ }
+
/// Generate a new private key asynchronously. The new keys will be sent to the daemon channel.
pub fn generate_key_async(&mut self, account: AccountToken) -> Result<()> {
@@ -160,11 +177,9 @@ impl KeyManager {
.max_delay(Duration::from_secs(60 * 60))
.map(jitter);
- let should_retry = |err: &jsonrpc_client_core::Error| -> bool {
- match err.kind() {
- jsonrpc_client_core::ErrorKind::JsonRpcError(err)
- if err.code.code() == TOO_MANY_KEYS_ERROR_CODE =>
- {
+ let should_retry = |err: &RestError| -> bool {
+ match err {
+ RestError::ApiError(_status, code) if code == mullvad_rpc::KEY_LIMIT_REACHED => {
false
}
_ => true,
@@ -225,13 +240,13 @@ impl KeyManager {
&self,
account: AccountToken,
private_key: PrivateKey,
- ) -> Box<dyn FnMut() -> Box<dyn Future<Item = WireguardData, Error = JsonRpcError> + Send> + Send>
+ ) -> Box<dyn FnMut() -> Box<dyn Future<Item = WireguardData, Error = RestError> + Send> + Send>
{
let mut rpc = mullvad_rpc::WireguardKeyProxy::new(self.http_handle.clone());
let public_key = private_key.public_key();
let push_future =
- move || -> Box<dyn Future<Item = WireguardData, Error = JsonRpcError> + Send> {
+ move || -> Box<dyn Future<Item = WireguardData, Error = RestError> + Send> {
let key = private_key.clone();
Box::new(rpc.push_wg_key(account.clone(), public_key.clone()).map(
move |addresses| WireguardData {
@@ -245,7 +260,7 @@ impl KeyManager {
}
fn replace_key_rpc(
- http_handle: mullvad_rpc::HttpHandle,
+ http_handle: MullvadRestHandle,
account: AccountToken,
old_key: PublicKey,
new_key: PrivateKey,
@@ -261,13 +276,16 @@ impl KeyManager {
})
}
- fn map_rpc_error(err: jsonrpc_client_core::Error) -> Error {
- match err.kind() {
+ fn map_rpc_error(err: mullvad_rpc::rest::Error) -> Error {
+ match &err {
// TODO: Consider handling the invalid account case too.
- jsonrpc_client_core::ErrorKind::JsonRpcError(err) if err.code.code() == -703 => {
+ mullvad_rpc::rest::Error::ApiError(status, message)
+ if *status == mullvad_rpc::StatusCode::BAD_REQUEST
+ && message == mullvad_rpc::KEY_LIMIT_REACHED =>
+ {
Error::TooManyKeys
}
- _ => Error::RpcError(err),
+ _ => Error::RestError(err),
}
}
@@ -290,7 +308,7 @@ impl KeyManager {
fn next_automatic_rotation(
daemon_tx: DaemonEventSender,
- http_handle: mullvad_rpc::HttpHandle,
+ http_handle: MullvadRestHandle,
public_key: PublicKey,
rotation_interval_secs: u64,
account_token: AccountToken,
@@ -330,7 +348,7 @@ impl KeyManager {
fn create_automatic_rotation(
daemon_tx: DaemonEventSender,
- http_handle: mullvad_rpc::HttpHandle,
+ http_handle: MullvadRestHandle,
public_key: PublicKey,
rotation_interval_secs: u64,
account_token: AccountToken,
@@ -355,8 +373,8 @@ impl KeyManager {
}
Err(e) => {
log::error!(
- "Key rotation failed: {}. Retrying in {} seconds",
- e,
+ "{}. Retrying in {} seconds",
+ e.display_chain_with_msg("Key rotation failed:"),
AUTOMATIC_ROTATION_RETRY_DELAY.as_secs(),
);
Ok(old_public_key)