summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2024-02-07 23:20:47 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2024-02-08 10:50:58 +0100
commit6effbc46664b741f702adc0168053f46fa44dd41 (patch)
tree218c526e08b9d3143a0757bfdbfc923b26331553
parent1b80203504f58fab47dc6dbe53f223084acecc6a (diff)
downloadmullvadvpn-6effbc46664b741f702adc0168053f46fa44dd41.tar.xz
mullvadvpn-6effbc46664b741f702adc0168053f46fa44dd41.zip
Add support for custom lists in jni
-rw-r--r--mullvad-jni/src/classes.rs2
-rw-r--r--mullvad-jni/src/daemon_interface.rs31
-rw-r--r--mullvad-jni/src/lib.rs70
-rw-r--r--mullvad-types/src/custom_list.rs47
-rw-r--r--mullvad-types/src/settings/mod.rs1
5 files changed, 150 insertions, 1 deletions
diff --git a/mullvad-jni/src/classes.rs b/mullvad-jni/src/classes.rs
index 454e0e6c62..562fe786f0 100644
--- a/mullvad-jni/src/classes.rs
+++ b/mullvad-jni/src/classes.rs
@@ -9,6 +9,8 @@ pub const CLASSES: &[&str] = &[
"net/mullvad/mullvadvpn/model/AppVersionInfo",
"net/mullvad/mullvadvpn/model/Constraint$Any",
"net/mullvad/mullvadvpn/model/Constraint$Only",
+ "net/mullvad/mullvadvpn/model/CustomList",
+ "net/mullvad/mullvadvpn/model/CustomListsSettings",
"net/mullvad/mullvadvpn/model/DnsState",
"net/mullvad/mullvadvpn/model/DnsOptions",
"net/mullvad/mullvadvpn/model/CustomDnsOptions",
diff --git a/mullvad-jni/src/daemon_interface.rs b/mullvad-jni/src/daemon_interface.rs
index 7ecc91585a..7abd35cf5b 100644
--- a/mullvad-jni/src/daemon_interface.rs
+++ b/mullvad-jni/src/daemon_interface.rs
@@ -2,6 +2,7 @@ use futures::{channel::oneshot, executor::block_on};
use mullvad_daemon::{device, DaemonCommand, DaemonCommandSender};
use mullvad_types::{
account::{AccountData, AccountToken, PlayPurchase, VoucherSubmission},
+ custom_list::CustomList,
device::{Device, DeviceState},
relay_constraints::{ObfuscationSettings, RelaySettings},
relay_list::RelayList,
@@ -354,6 +355,36 @@ impl DaemonInterface {
.map_err(|_| Error::UpdateSettings)
}
+ pub fn create_custom_list(&self, name: String) -> Result<mullvad_types::custom_list::Id> {
+ let (tx, rx) = oneshot::channel();
+
+ self.send_command(DaemonCommand::CreateCustomList(tx, name))?;
+
+ block_on(rx)
+ .map_err(|_| Error::NoResponse)?
+ .map_err(Error::from)
+ }
+
+ pub fn delete_custom_list(&self, id: mullvad_types::custom_list::Id) -> Result<()> {
+ let (tx, rx) = oneshot::channel();
+
+ self.send_command(DaemonCommand::DeleteCustomList(tx, id))?;
+
+ block_on(rx)
+ .map_err(|_| Error::NoResponse)?
+ .map_err(Error::from)
+ }
+
+ pub fn update_custom_list(&self, custom_list: CustomList) -> Result<()> {
+ let (tx, rx) = oneshot::channel();
+
+ self.send_command(DaemonCommand::UpdateCustomList(tx, custom_list))?;
+
+ block_on(rx)
+ .map_err(|_| Error::NoResponse)?
+ .map_err(Error::from)
+ }
+
fn send_command(&self, command: DaemonCommand) -> Result<()> {
self.command_sender.send(command).map_err(Error::NoDaemon)
}
diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs
index a41b8d6643..1416fd70b5 100644
--- a/mullvad-jni/src/lib.rs
+++ b/mullvad-jni/src/lib.rs
@@ -24,6 +24,7 @@ use mullvad_daemon::{
};
use mullvad_types::{
account::{AccountData, PlayPurchase, VoucherSubmission},
+ custom_list::CustomList,
settings::DnsOptions,
};
use std::{
@@ -1338,6 +1339,75 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_setQuan
}
}
+#[no_mangle]
+#[allow(non_snake_case)]
+pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_createCustomList<'env>(
+ env: JNIEnv<'env>,
+ _: JObject<'_>,
+ daemon_interface_address: jlong,
+ name: JString<'_>,
+) -> JObject<'env> {
+ let env = JnixEnv::from(env);
+
+ // SAFETY: The address points to an instance valid for the duration of this function call
+ if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } {
+ let name = String::from_java(&env, name);
+ match daemon_interface.create_custom_list(name) {
+ Ok(id) => id.into_java(&env).forget(),
+ Err(error) => {
+ log_request_error("create custom list", &error);
+ JObject::null()
+ }
+ }
+ } else {
+ JObject::null()
+ }
+}
+
+#[no_mangle]
+#[allow(non_snake_case)]
+pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_deleteCustomList(
+ env: JNIEnv<'_>,
+ _: JObject<'_>,
+ daemon_interface_address: jlong,
+ id: JString<'_>,
+) {
+ let env = JnixEnv::from(env);
+
+ // SAFETY: The address points to an instance valid for the duration of this function call
+ if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } {
+ let id = mullvad_types::custom_list::Id::from_java(&env, id);
+ if let Err(error) = daemon_interface.delete_custom_list(id) {
+ log::error!(
+ "{}",
+ error.display_chain_with_msg("Failed to delete custom list")
+ );
+ }
+ }
+}
+
+#[no_mangle]
+#[allow(non_snake_case)]
+pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_updateCustomList(
+ env: JNIEnv<'_>,
+ _: JObject<'_>,
+ daemon_interface_address: jlong,
+ customList: JObject<'_>,
+) {
+ let env = JnixEnv::from(env);
+
+ // SAFETY: The address points to an instance valid for the duration of this function call
+ if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } {
+ let list = CustomList::from_java(&env, customList);
+ if let Err(error) = daemon_interface.update_custom_list(list) {
+ log::error!(
+ "{}",
+ error.display_chain_with_msg("Failed to update custom list")
+ );
+ }
+ }
+}
+
fn log_request_error(request: &str, error: &daemon_interface::Error) {
match error {
daemon_interface::Error::Api(RestError::Aborted) => {
diff --git a/mullvad-types/src/custom_list.rs b/mullvad-types/src/custom_list.rs
index 58fd046a9e..b92f128a3b 100644
--- a/mullvad-types/src/custom_list.rs
+++ b/mullvad-types/src/custom_list.rs
@@ -77,6 +77,8 @@ impl<'borrow, 'env: 'borrow> IntoJava<'borrow, 'env> for Id {
}
}
+#[cfg_attr(target_os = "android", derive(IntoJava, FromJava))]
+#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))]
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CustomListsSettings {
custom_lists: Vec<CustomList>,
@@ -122,9 +124,17 @@ impl DerefMut for CustomListsSettings {
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[cfg_attr(target_os = "android", derive(IntoJava))]
+#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))]
pub struct CustomList {
pub id: Id,
pub name: String,
+ #[cfg_attr(
+ target_os = "android",
+ jnix(
+ map = "|locations| locations.into_iter().collect::<Vec<GeographicLocationConstraint>>()"
+ )
+ )]
pub locations: BTreeSet<GeographicLocationConstraint>,
}
@@ -137,3 +147,40 @@ impl CustomList {
}
}
}
+
+#[cfg(target_os = "android")]
+impl<'env, 'sub_env> FromJava<'env, JObject<'sub_env>> for CustomList
+where
+ 'env: 'sub_env,
+{
+ const JNI_SIGNATURE: &'static str = "Lnet/mullvad/mullvadvpn/model/CustomList;";
+
+ fn from_java(env: &JnixEnv<'env>, source: JObject<'sub_env>) -> Self {
+ let object_id = env
+ .call_method(source, "component1", "()Ljava/lang/String;", &[])
+ .expect("missing CustomList.id")
+ .l()
+ .expect("CustomList.id did not return an object");
+ let id = Id::from_str(&String::from_java(env, object_id)).expect("invalid ID");
+
+ let object_name = env
+ .call_method(source, "component2", "()Ljava/lang/String;", &[])
+ .expect("missing CustomList.name")
+ .l()
+ .expect("CustomList.name did not return an object");
+ let name = String::from_java(env, object_name);
+
+ let object_locations = env
+ .call_method(source, "component3", "()Ljava/util/ArrayList;", &[])
+ .expect("missing CustomList.locations")
+ .l()
+ .expect("CustomList.locations did not return an object");
+ let locations = BTreeSet::from_iter(Vec::from_java(env, object_locations));
+
+ CustomList {
+ id,
+ name,
+ locations,
+ }
+ }
+}
diff --git a/mullvad-types/src/settings/mod.rs b/mullvad-types/src/settings/mod.rs
index 3adde14b5d..607e1d9539 100644
--- a/mullvad-types/src/settings/mod.rs
+++ b/mullvad-types/src/settings/mod.rs
@@ -77,7 +77,6 @@ pub struct Settings {
#[cfg_attr(target_os = "android", jnix(skip))]
pub bridge_state: BridgeState,
/// All of the custom relay lists
- #[cfg_attr(target_os = "android", jnix(skip))]
pub custom_lists: CustomListsSettings,
/// API access methods
#[cfg_attr(target_os = "android", jnix(skip))]