summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt19
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt5
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt1
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt9
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt240
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/KeyStatusListener.kt23
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/model/KeygenEvent.kt2
-rw-r--r--android/src/main/res/layout/settings.xml28
-rw-r--r--android/src/main/res/layout/wireguard_key.xml153
-rw-r--r--android/src/main/res/values/strings.xml17
-rw-r--r--mullvad-jni/src/daemon_interface.rs7
-rw-r--r--mullvad-jni/src/into_java.rs8
-rw-r--r--mullvad-jni/src/lib.rs27
13 files changed, 513 insertions, 26 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
index 45dfb620a5..1e7f16e94d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ConnectFragment.kt
@@ -90,12 +90,6 @@ class ConnectFragment : Fragment() {
switchLocationButton.onClick = { openSwitchLocationScreen() }
updateKeyStatusJob = updateKeyStatus(keyStatusListener.keyStatus)
- updateTunnelStateJob = updateTunnelState(connectionProxy.uiState)
-
- connectionProxy.onUiStateChange = { uiState ->
- updateTunnelStateJob.cancel()
- updateTunnelStateJob = updateTunnelState(uiState)
- }
return view
}
@@ -119,6 +113,12 @@ class ConnectFragment : Fragment() {
relayListListener.onRelayListChange = { relayList, selectedRelayItem ->
switchLocationButton.location = selectedRelayItem
}
+
+ updateTunnelStateJob = updateTunnelState(connectionProxy.uiState)
+ connectionProxy.onUiStateChange = { uiState ->
+ updateTunnelStateJob.cancel()
+ updateTunnelStateJob = updateTunnelState(uiState)
+ }
}
override fun onPause() {
@@ -126,6 +126,10 @@ class ConnectFragment : Fragment() {
locationInfoCache.onNewLocation = null
relayListListener.onRelayListChange = null
+ connectionProxy.onUiStateChange = null
+ updateTunnelStateJob.cancel()
+
+
isTunnelInfoExpanded = locationInfo.isTunnelInfoExpanded
notificationBanner.onPause()
@@ -136,9 +140,6 @@ class ConnectFragment : Fragment() {
override fun onDestroyView() {
switchLocationButton.onDestroy()
- connectionProxy.onUiStateChange = null
- updateTunnelStateJob.cancel()
-
super.onDestroyView()
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
index 15d33fbb04..ffc11354ff 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MainActivity.kt
@@ -99,11 +99,6 @@ class MainActivity : FragmentActivity() {
}
}
- override fun onResume() {
- super.onResume()
- keyStatusListener.onResume()
- }
-
override fun onStop() {
if (shouldStopService) {
runBlocking { service.await().stop() }
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
index 06b580d013..940fabbf77 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/MullvadDaemon.kt
@@ -35,6 +35,7 @@ class MullvadDaemon(val vpnService: MullvadVpnService) {
external fun setAccount(accountToken: String?)
external fun shutdown()
external fun updateRelaySettings(update: RelaySettingsUpdate)
+ external fun verifyWireguardKey(): Boolean?
private external fun initialize(vpnService: MullvadVpnService)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt
index ed9c2bf4ea..8465a66140 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/SettingsFragment.kt
@@ -55,8 +55,11 @@ class SettingsFragment : Fragment() {
view.findViewById<View>(R.id.account).setOnClickListener {
openSubFragment(AccountFragment())
}
+ view.findViewById<View>(R.id.wireguard_keys).setOnClickListener {
+ openSubFragment(WireguardKeyFragment())
+ }
view.findViewById<View>(R.id.app_version).setOnClickListener {
- openLink("https://mullvad.net/download/")
+ openLink(R.string.download_url)
}
view.findViewById<View>(R.id.report_a_problem).setOnClickListener {
openSubFragment(ProblemReportFragment())
@@ -104,8 +107,8 @@ class SettingsFragment : Fragment() {
}
}
- private fun openLink(url: String) {
- val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ private fun openLink(urlResourceId: Int) {
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(parentActivity.getString(urlResourceId)))
startActivity(intent)
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt
new file mode 100644
index 0000000000..e8be9d7228
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/WireguardKeyFragment.kt
@@ -0,0 +1,240 @@
+package net.mullvad.mullvadvpn
+
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.util.Base64
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ProgressBar
+import android.widget.TextView
+import android.widget.Toast
+
+import net.mullvad.mullvadvpn.dataproxy.ConnectionProxy
+import net.mullvad.mullvadvpn.dataproxy.KeyStatusListener
+import net.mullvad.mullvadvpn.model.KeygenEvent
+import net.mullvad.mullvadvpn.model.TunnelState
+
+class WireguardKeyFragment : Fragment() {
+ private var TAG = "keyfragment";
+ private var keyState: KeygenEvent? = null;
+ private var currentJob: Job? = null;
+ private var updateViewsJob: Job? = null;
+ private lateinit var parentActivity: MainActivity
+ private lateinit var connectionProxy: ConnectionProxy
+ private lateinit var keyStatusListener: KeyStatusListener
+ private var generatingKey = false
+ private var validatingKey = false
+
+ private lateinit var publicKey: TextView
+ private lateinit var statusMessage: TextView
+ private lateinit var visitWebsiteView: View
+ private lateinit var actionButton: Button
+ private lateinit var actionSpinner: ProgressBar
+
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ parentActivity = context as MainActivity
+ keyStatusListener = parentActivity.keyStatusListener
+ connectionProxy = parentActivity.connectionProxy
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ val view = inflater.inflate(R.layout.wireguard_key, container, false)
+
+ view.findViewById<View>(R.id.back).setOnClickListener {
+ parentActivity.onBackPressed()
+ }
+
+
+ statusMessage = view.findViewById<TextView>(R.id.wireguard_key_status)
+ visitWebsiteView = view.findViewById<View>(R.id.wireguard_key_visit_website)
+ publicKey = view.findViewById<TextView>(R.id.wireguard_public_key)
+ actionButton = view.findViewById<Button>(R.id.wg_key_button)
+ actionSpinner = view.findViewById<ProgressBar>(R.id.wg_action_spinner)
+
+ updateViews()
+
+ connectionProxy.onUiStateChange = { _ ->
+ updateViewsJob?.cancel()
+ updateViewsJob = updateViewJob()
+ }
+
+ keyStatusListener.onKeyStatusChange = { _ ->
+ updateViewsJob?.cancel()
+ updateViewsJob = updateViewJob()
+ }
+
+ return view
+ }
+
+ private fun updateViewJob() = GlobalScope.launch(Dispatchers.Main) {
+ updateViews()
+ }
+
+
+ private fun updateViews() {
+ clearErrorMessage()
+ visitWebsiteView.visibility = View.GONE
+
+ actionButton.setClickable(true)
+
+ when (val keyState = keyStatusListener.keyStatus) {
+ null -> {
+ publicKey.visibility = View.INVISIBLE
+ setGenerateButton()
+ }
+ is KeygenEvent.TooManyKeys -> {
+ visitWebsiteView.visibility = View.VISIBLE
+ visitWebsiteView.setOnClickListener {
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(parentActivity.getString(R.string.account_url)))
+ startActivity(intent)
+ }
+
+ setStatusMessage(R.string.too_many_keys, R.color.red)
+ setGenerateButton()
+ }
+ is KeygenEvent.GenerationFailure -> {
+ setStatusMessage(R.string.failed_to_generate_key, R.color.red)
+ setGenerateButton()
+ }
+ is KeygenEvent.NewKey -> {
+ val publicKeyString = Base64.encodeToString(keyState.publicKey.key, Base64.DEFAULT)
+ publicKey.visibility = View.VISIBLE
+ publicKey.setText(publicKeyString)
+
+ setValidateButton()
+
+ if (keyState.verified != null) {
+ if (keyState.verified) {
+ setStatusMessage(R.string.wireguard_key_valid, R.color.green)
+ } else {
+ setStatusMessage(R.string.wireguard_key_invalid, R.color.red)
+ setGenerateButton()
+ }
+ }
+ }
+ }
+ drawNoConnectionState()
+ }
+
+ private fun setStatusMessage(message: Int, color: Int) {
+ statusMessage.setText(message)
+ statusMessage.setTextColor(parentActivity.getColor(color))
+ statusMessage.visibility = View.VISIBLE
+ }
+
+ private fun clearErrorMessage() {
+ statusMessage.visibility = View.GONE
+ }
+
+ private fun setGenerateButton() {
+ if (generatingKey) {
+ showActionSpinner()
+ return;
+ }
+ actionSpinner.visibility = View.GONE
+ actionButton.visibility = View.VISIBLE
+ actionButton.setText(R.string.wireguard_generate_key)
+ actionButton.setOnClickListener {
+ onGenerateKeyPress()
+ }
+ }
+
+ private fun setValidateButton() {
+ if (validatingKey) {
+ showActionSpinner()
+ return;
+ }
+ actionSpinner.visibility = View.GONE
+ actionButton.visibility = View.VISIBLE
+ actionButton.setText(R.string.wireguard_validate_key)
+ actionButton.setOnClickListener {
+ onValidateKeyPress()
+ }
+ }
+
+ private fun showActionSpinner() {
+ actionButton.visibility = View.GONE
+ actionSpinner.visibility = View.VISIBLE
+ }
+
+ private fun drawNoConnectionState() {
+ when (connectionProxy.state) {
+ is TunnelState.Connecting, is TunnelState.Disconnecting -> {
+ statusMessage.setText(R.string.wireguard_key_connectivity)
+ statusMessage.visibility = View.VISIBLE
+ actionButton.visibility = View.GONE
+ actionSpinner.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ private fun onGenerateKeyPress() {
+ currentJob?.cancel()
+ generatingKey = true;
+ validatingKey = false;
+ updateViews()
+ currentJob = GlobalScope.launch(Dispatchers.Main) {
+ keyStatusListener.generateKey().join()
+ generatingKey = false;
+ updateViews()
+ }
+ }
+
+ private fun onValidateKeyPress() {
+ currentJob?.cancel()
+ validatingKey = true;
+ generatingKey = false;
+ updateViews()
+ currentJob = GlobalScope.launch(Dispatchers.Main) {
+ keyStatusListener.verifyKey().join()
+ validatingKey = false;
+ when (val state = keyStatusListener.keyStatus) {
+ is KeygenEvent.NewKey -> {
+ if (state.verified == null) {
+ Toast.makeText(parentActivity, R.string.wireguard_key_verification_failure, Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ updateViews()
+ }
+ }
+
+ override fun onPause() {
+ connectionProxy.onUiStateChange = null
+ keyStatusListener.onKeyStatusChange = null
+ currentJob?.cancel()
+ updateViewsJob?.cancel()
+ validatingKey = false;
+ generatingKey = false;
+ super.onPause()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ connectionProxy.onUiStateChange = { _ ->
+ updateViewsJob?.cancel()
+ updateViewsJob = updateViewJob()
+ }
+
+ keyStatusListener.onKeyStatusChange = { _ ->
+ updateViewsJob?.cancel()
+ updateViewsJob = updateViewJob()
+ }
+ }
+}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/KeyStatusListener.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/KeyStatusListener.kt
index 66b7a96e44..74ad587eea 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/KeyStatusListener.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/KeyStatusListener.kt
@@ -38,13 +38,26 @@ class KeyStatusListener(val asyncDaemon: Deferred<MullvadDaemon>) {
private fun setUp() = GlobalScope.launch(Dispatchers.Default) {
daemon = asyncDaemon.await()
daemon?.onKeygenEvent = { event -> keyStatus = event }
+ val wireguardKey = daemon?.getWireguardKey()
+ if (wireguardKey != null) {
+ keyStatus = KeygenEvent.NewKey(wireguardKey, null)
+ }
}
- fun onResume() {
- if (keyStatus is KeygenEvent.TooManyKeys || keyStatus is KeygenEvent.GenerationFailure) {
- retryJob?.cancel()
- retryJob = retryKeyGeneration()
- }
+ fun generateKey() = GlobalScope.launch(Dispatchers.Default) {
+ setUpJob.join()
+ keyStatus = daemon?.generateWireguardKey()
+ }
+
+ fun verifyKey() = GlobalScope.launch(Dispatchers.Default) {
+ setUpJob.join()
+ val verified = daemon?.verifyWireguardKey()
+ // Only update verification status if the key is actually there
+ when (val state = keyStatus) {
+ is KeygenEvent.NewKey -> {
+ keyStatus = KeygenEvent.NewKey(state.publicKey, verified)
+ }
+ }
}
fun onDestroy() {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/KeygenEvent.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/KeygenEvent.kt
index b5938d65f6..b93794d44c 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/model/KeygenEvent.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/model/KeygenEvent.kt
@@ -1,7 +1,7 @@
package net.mullvad.mullvadvpn.model
sealed class KeygenEvent {
- class NewKey(var publicKey: PublicKey) : KeygenEvent()
+ class NewKey(val publicKey: PublicKey, val verified: Boolean?) : KeygenEvent()
class TooManyKeys : KeygenEvent()
class GenerationFailure : KeygenEvent()
}
diff --git a/android/src/main/res/layout/settings.xml b/android/src/main/res/layout/settings.xml
index d0308f163b..7b4161406a 100644
--- a/android/src/main/res/layout/settings.xml
+++ b/android/src/main/res/layout/settings.xml
@@ -64,6 +64,34 @@
android:src="@drawable/icon_chevron"
/>
</LinearLayout>
+ <LinearLayout android:id="@+id/wireguard_keys"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="16dp"
+ android:layout_marginTop="24dp"
+ android:background="@drawable/cell_button_background"
+ android:clickable="true"
+ android:gravity="center"
+ >
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingHorizontal="8dp"
+ android:paddingVertical="17dp"
+ android:textColor="@color/white"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ android:text="@string/wireguard_key"
+ />
+ <ImageView
+ android:layout_width="14dp"
+ android:layout_height="24dp"
+ android:layout_weight="0"
+ android:alpha="0.6"
+ android:src="@drawable/icon_chevron"
+ />
+ </LinearLayout>
<LinearLayout android:id="@+id/app_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/android/src/main/res/layout/wireguard_key.xml b/android/src/main/res/layout/wireguard_key.xml
new file mode 100644
index 0000000000..b0da0776ca
--- /dev/null
+++ b/android/src/main/res/layout/wireguard_key.xml
@@ -0,0 +1,153 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/darkBlue"
+ android:elevation="3dp"
+ android:gravity="left"
+ android:orientation="vertical">
+
+ <LinearLayout android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="12dp"
+ android:orientation="horizontal"
+ android:gravity="center_vertical | left"
+ android:clickable="true"
+ android:background="?android:attr/selectableItemBackground"
+ >
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginRight="8dp"
+ android:src="@drawable/icon_back"
+ />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white60"
+ android:textSize="13sp"
+ android:textStyle="bold"
+ android:text="@string/settings"
+ />
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="24dp"
+ android:text="@string/wireguard_key"
+ android:textColor="@color/white"
+ android:textSize="32sp"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:id="@+id/wireguard_public_key_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/cell_button_background"
+ android:clickable="true"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:paddingHorizontal="4dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="10dp"
+ android:paddingBottom="5dp"
+ android:text="@string/wireguard_public_key"
+ android:textColor="@color/white"
+ android:textSize="20sp"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/wireguard_public_key"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:paddingTop="3dp"
+ android:textAllCaps="true"
+ android:textColor="@color/white60"
+ android:textSize="14sp"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/wireguard_key_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="5dp"
+ android:textColor="@color/red"
+ android:textSize="20sp"
+ android:textStyle="bold"
+ android:visibility="gone" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/wireguard_key_visit_website"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:background="@drawable/cell_button_background"
+ android:clickable="true"
+ android:gravity="center"
+ android:paddingHorizontal="16dp"
+ android:visibility="gone">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="8dp"
+ android:paddingVertical="17dp"
+ android:text="@string/wireguard_key_visit_website"
+ android:textColor="@color/white"
+ android:textSize="20sp"
+ android:textStyle="bold" />
+
+ <ImageView
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:alpha="0.6"
+ android:src="@drawable/icon_extlink" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/wireguard_button_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="15dp"
+ android:layout_marginBottom="15dp"
+ android:background="@drawable/cell_button_background"
+ android:clickable="true"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="50dp"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/wg_key_button"
+ style="@style/Button"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:text="@string/wireguard_validate_key"/>
+
+ <ProgressBar
+ android:id="@+id/wg_action_spinner"
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ android:indeterminate="true"
+ android:indeterminateDrawable="@drawable/icon_spinner"
+ android:indeterminateDuration="600"
+ android:indeterminateOnly="true"
+ android:visibility="gone" />
+ </RelativeLayout>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml
index 6b605a7bc2..02f4315083 100644
--- a/android/src/main/res/values/strings.xml
+++ b/android/src/main/res/values/strings.xml
@@ -95,6 +95,23 @@
While connected, your real location is masked with a private and secure location in the
selected region
</string>
+ <string name="wireguard_key">WireGuard key</string>
+ <string name="wireguard_public_key">Public key</string>
+ <string name="wireguard_validate_key">Validate key</string>
+ <string name="wireguard_generate_key">Generate key</string>
+ <string name="wireguard_key_visit_website">Manage your keys on website</string>
+ <string name="wireguard_key_connectivity">
+ Connectivity required to manage your key.
+ </string>
+ <string name="wireguard_key_valid">
+ Key is valid
+ </string>
+ <string name="wireguard_key_invalid">
+ Key is invalid
+ </string>
+ <string name="wireguard_key_verification_failure">
+ Failed to validate key
+ </string>
<string name="account_url">https://mullvad.net/en/account</string>
<string name="download_url">https://mullvad.net/en/download</string>
diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs
index 80c3abec26..f80c645bb6 100644
--- a/mullvad-jni/src/daemon_interface.rs
+++ b/mullvad-jni/src/daemon_interface.rs
@@ -148,6 +148,13 @@ impl DaemonInterface {
rx.wait().map_err(|_| Error::NoResponse)
}
+ pub fn verify_wireguard_key(&self) -> Result<bool> {
+ let (tx, rx) = oneshot::channel();
+
+ self.send_command(ManagementCommand::VerifyWireguardKey(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 b726e27bdf..b927014178 100644
--- a/mullvad-jni/src/into_java.rs
+++ b/mullvad-jni/src/into_java.rs
@@ -547,11 +547,15 @@ impl<'env> IntoJava<'env> for KeygenEvent {
KeygenEvent::NewKey(public_key) => {
let class = get_class("net/mullvad/mullvadvpn/model/KeygenEvent$NewKey");
let java_public_key = env.auto_local(public_key.into_java(env));
- let parameters = [JValue::Object(java_public_key.as_obj())];
+
+ let parameters = [
+ JValue::Object(java_public_key.as_obj()),
+ JValue::Object(JObject::null()),
+ ];
env.new_object(
&class,
- "(Lnet/mullvad/mullvadvpn/model/PublicKey;)V",
+ "(Lnet/mullvad/mullvadvpn/model/PublicKey;Ljava/lang/Boolean;)V",
&parameters,
)
.expect("Failed to create KeygenEvent.NewKey Java object")
diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs
index 28c68e422f..c8d267bb8b 100644
--- a/mullvad-jni/src/lib.rs
+++ b/mullvad-jni/src/lib.rs
@@ -12,7 +12,7 @@ use crate::{
jni_event_listener::JniEventListener, vpn_service_tun_provider::VpnServiceTunProvider,
};
use jni::{
- objects::{GlobalRef, JObject, JString},
+ objects::{GlobalRef, JObject, JString, JValue},
sys::{jboolean, JNI_FALSE, JNI_TRUE},
JNIEnv,
};
@@ -30,6 +30,7 @@ use talpid_types::ErrorExt;
const LOG_FILENAME: &str = "daemon.log";
const CLASSES_TO_LOAD: &[&str] = &[
+ "java/lang/Boolean",
"java/net/InetAddress",
"java/net/InetSocketAddress",
"java/util/ArrayList",
@@ -275,6 +276,30 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_generateWiregua
#[no_mangle]
#[allow(non_snake_case)]
+pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_verifyWireguardKey<'env, 'this>(
+ env: JNIEnv<'env>,
+ _: JObject<'this>,
+) -> JObject<'env> {
+ match DAEMON_INTERFACE.verify_wireguard_key() {
+ Ok(key_is_valid) => env
+ .new_object(
+ &get_class("java/lang/Boolean"),
+ "(Z)V",
+ &[JValue::Bool(key_is_valid as jboolean)],
+ )
+ .expect("Failed to create Boolean Java object"),
+ Err(error) => {
+ log::error!(
+ "{}",
+ error.display_chain_with_msg("Failed to verify wireguard key")
+ );
+ JObject::null()
+ }
+ }
+}
+
+#[no_mangle]
+#[allow(non_snake_case)]
pub extern "system" fn Java_net_mullvad_mullvadvpn_MullvadDaemon_getAccountData<'env, 'this>(
env: JNIEnv<'env>,
_: JObject<'this>,