diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-27 08:24:24 -0300 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2019-05-27 08:24:24 -0300 |
| commit | b8f08c59ab655a2fdc7a71c8abf5895a85758a14 (patch) | |
| tree | c1233dbefa25db09722e643b32d92a3d3950c402 | |
| parent | 513b791fd21fabfa8b9990b34eeb8a1871110a4a (diff) | |
| parent | b5243e12d97f084a374de209952a6740ec9c407f (diff) | |
| download | mullvadvpn-b8f08c59ab655a2fdc7a71c8abf5895a85758a14.tar.xz mullvadvpn-b8f08c59ab655a2fdc7a71c8abf5895a85758a14.zip | |
Merge branch 'wireguard-key-generation-on-android'
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt | 55 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt | 3 | ||||
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt | 3 | ||||
| -rw-r--r-- | mullvad-jni/src/daemon_interface.rs | 19 | ||||
| -rw-r--r-- | mullvad-jni/src/into_java.rs | 35 | ||||
| -rw-r--r-- | mullvad-jni/src/lib.rs | 42 |
6 files changed, 148 insertions, 9 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt index 11bfabe912..4a853b2f7b 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt @@ -1,6 +1,7 @@ package net.mullvad.mullvadvpn import kotlinx.coroutines.launch +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope @@ -23,15 +24,19 @@ class ConnectFragment : Fragment() { private lateinit var notificationBanner: NotificationBanner private lateinit var status: ConnectionStatus - private lateinit var daemon: Deferred<MullvadDaemon> + private var daemon = CompletableDeferred<MullvadDaemon>() + private var generateWireguardKeyJob = generateWireguardKey() + + private var activeAction: Job? = null private var attachListenerJob: Job? = null private var updateViewJob: Job? = null + private var waitForDaemonJob: Job? = null override fun onAttach(context: Context) { super.onAttach(context) - daemon = (context as MainActivity).asyncDaemon + waitForDaemonJob = waitForDaemon((context as MainActivity).asyncDaemon) } override fun onCreateView( @@ -61,14 +66,20 @@ class ConnectFragment : Fragment() { return view } - override fun onDestroyView() { + waitForDaemonJob?.cancel() attachListenerJob?.cancel() detachListener() + generateWireguardKeyJob.cancel() updateViewJob?.cancel() super.onDestroyView() } + private fun waitForDaemon(asyncDaemon: Deferred<MullvadDaemon>) = + GlobalScope.launch(Dispatchers.Default) { + daemon.complete(asyncDaemon.await()) + } + private fun attachListener() = GlobalScope.launch(Dispatchers.Default) { daemon.await().onTunnelStateChange = { state -> updateViewJob = updateView(state) } } @@ -77,12 +88,42 @@ class ConnectFragment : Fragment() { daemon.await().onTunnelStateChange = null } - private fun connect() = GlobalScope.launch(Dispatchers.Default) { - daemon.await().connect() + private fun generateWireguardKey() = GlobalScope.launch(Dispatchers.Default) { + val daemon = this@ConnectFragment.daemon.await() + val key = daemon.getWireguardKey() + + if (key == null) { + daemon.generateWireguardKey() + } + } + + private fun connect() { + updateViewToPreConnecting() + activeAction?.cancel() + + activeAction = GlobalScope.launch(Dispatchers.Default) { + generateWireguardKeyJob.join() + daemon.await().connect() + } + } + + private fun disconnect() { + activeAction?.cancel() + + activeAction = GlobalScope.launch(Dispatchers.Default) { + daemon.await().disconnect() + } } - private fun disconnect() = GlobalScope.launch(Dispatchers.Default) { - daemon.await().disconnect() + private fun updateViewToPreConnecting() { + val connecting = TunnelStateTransition.Connecting() + val disconnected = TunnelStateTransition.Disconnected() + + headerBar.setState(disconnected) + + actionButton.state = connecting + notificationBanner.setState(connecting) + status.setState(connecting) } private fun updateView(state: TunnelStateTransition) = GlobalScope.launch(Dispatchers.Main) { diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt index 80ac09eef2..e9f54769b2 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt @@ -1,6 +1,7 @@ package net.mullvad.mullvadvpn import net.mullvad.mullvadvpn.model.AccountData +import net.mullvad.mullvadvpn.model.PublicKey import net.mullvad.mullvadvpn.model.RelayList import net.mullvad.mullvadvpn.model.RelaySettingsUpdate import net.mullvad.mullvadvpn.model.Settings @@ -16,9 +17,11 @@ class MullvadDaemon { external fun connect() external fun disconnect() + external fun generateWireguardKey(): Boolean external fun getAccountData(accountToken: String): AccountData? external fun getRelayLocations(): RelayList external fun getSettings(): Settings + external fun getWireguardKey(): PublicKey? external fun setAccount(accountToken: String?) external fun updateRelaySettings(update: RelaySettingsUpdate) diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt new file mode 100644 index 0000000000..30408c4a9b --- /dev/null +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt @@ -0,0 +1,3 @@ +package net.mullvad.mullvadvpn.model + +data class PublicKey(val key: ByteArray) diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs index db14a92373..bb92ea9cc8 100644 --- a/mullvad-jni/src/daemon_interface.rs +++ b/mullvad-jni/src/daemon_interface.rs @@ -4,6 +4,7 @@ use mullvad_types::{ account::AccountData, relay_constraints::RelaySettingsUpdate, relay_list::RelayList, settings::Settings, states::TargetState, }; +use talpid_types::net::wireguard; #[derive(Debug, err_derive::Error)] pub enum Error { @@ -60,6 +61,16 @@ impl DaemonInterface { Ok(()) } + pub fn generate_wireguard_key(&self) -> Result<()> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::GenerateWireguardKey(tx))?; + + rx.wait() + .map_err(|_| Error::NoResponse)? + .map_err(Error::RpcError) + } + pub fn get_account_data(&self, account_token: String) -> Result<AccountData> { let (tx, rx) = oneshot::channel(); @@ -87,6 +98,14 @@ impl DaemonInterface { Ok(rx.wait().map_err(|_| Error::NoResponse)?) } + pub fn get_wireguard_key(&self) -> Result<Option<wireguard::PublicKey>> { + let (tx, rx) = oneshot::channel(); + + self.send_command(ManagementCommand::GetWireguardKey(tx))?; + + rx.wait().map_err(|_| Error::NoResponse) + } + pub fn set_account(&self, account_token: Option<String>) -> Result<()> { let (tx, rx) = oneshot::channel(); diff --git a/mullvad-jni/src/into_java.rs b/mullvad-jni/src/into_java.rs index 743328dbff..92d75b4a27 100644 --- a/mullvad-jni/src/into_java.rs +++ b/mullvad-jni/src/into_java.rs @@ -1,7 +1,7 @@ use crate::get_class; use jni::{ objects::{JList, JObject, JString, JValue}, - sys::jint, + sys::{jint, jsize}, JNIEnv, }; use mullvad_types::{ @@ -12,7 +12,7 @@ use mullvad_types::{ CustomTunnelEndpoint, }; use std::fmt::Debug; -use talpid_types::tunnel::TunnelStateTransition; +use talpid_types::{net::wireguard::PublicKey, tunnel::TunnelStateTransition}; pub trait IntoJava<'env> { type JavaType; @@ -73,6 +73,37 @@ where } } +impl<'array, 'env> IntoJava<'env> for &'array [u8] { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let size = self.len(); + let array = env + .new_byte_array(size as jsize) + .expect("Failed to create a Java array of bytes"); + + let data = unsafe { std::slice::from_raw_parts(self.as_ptr() as *const i8, size) }; + + env.set_byte_array_region(array, 0, data) + .expect("Failed to copy bytes to Java array"); + + JObject::from(array) + } +} + +impl<'env> IntoJava<'env> for PublicKey { + type JavaType = JObject<'env>; + + fn into_java(self, env: &JNIEnv<'env>) -> Self::JavaType { + let class = get_class("net/mullvad/mullvadvpn/model/PublicKey"); + let key = env.auto_local(self.as_bytes().into_java(env)); + let parameters = [JValue::Object(key.as_obj())]; + + env.new_object(&class, "([B)V", ¶meters) + .expect("Failed to create PublicKey Java object") + } +} + impl<'env> IntoJava<'env> for AccountData { type JavaType = JObject<'env>; diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs index 83e60e0486..9e1b0c3b38 100644 --- a/mullvad-jni/src/lib.rs +++ b/mullvad-jni/src/lib.rs @@ -12,6 +12,7 @@ use crate::{ }; use jni::{ objects::{GlobalRef, JObject, JString}, + sys::{jboolean, JNI_FALSE, JNI_TRUE}, JNIEnv, }; use lazy_static::lazy_static; @@ -30,6 +31,7 @@ const CLASSES_TO_LOAD: &[&str] = &[ "net/mullvad/mullvadvpn/model/LocationConstraint$City", "net/mullvad/mullvadvpn/model/LocationConstraint$Country", "net/mullvad/mullvadvpn/model/LocationConstraint$Hostname", + "net/mullvad/mullvadvpn/model/PublicKey", "net/mullvad/mullvadvpn/model/Relay", "net/mullvad/mullvadvpn/model/RelayList", "net/mullvad/mullvadvpn/model/RelayListCity", @@ -197,6 +199,26 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_disconnect(_: J #[no_mangle] #[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_generateWireguardKey( + _: JNIEnv, + _: JObject, +) -> jboolean { + let daemon = DAEMON_INTERFACE.lock(); + + match daemon.generate_wireguard_key() { + Ok(()) => JNI_TRUE, + Err(error) => { + log::error!( + "{}", + error.display_chain_with_msg("Failed to generate wireguard key") + ); + JNI_FALSE + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getAccountData<'env, 'this>( env: JNIEnv<'env>, _: JObject<'this>, @@ -257,6 +279,26 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getSettings<'en #[no_mangle] #[allow(non_snake_case)] +pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getWireguardKey<'env, 'this>( + env: JNIEnv<'env>, + _: JObject<'this>, +) -> JObject<'env> { + let daemon = DAEMON_INTERFACE.lock(); + + match daemon.get_wireguard_key() { + Ok(public_key) => public_key.into_java(&env), + Err(error) => { + log::error!( + "{}", + error.display_chain_with_msg("Failed to get wireguard key") + ); + JObject::null() + } + } +} + +#[no_mangle] +#[allow(non_snake_case)] pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_setAccount( env: JNIEnv, _: JObject, |
