diff options
| -rw-r--r-- | CHANGELOG.md | 3 | ||||
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceEvent.kt | 1 | ||||
| -rw-r--r-- | gui/src/main/daemon-rpc.ts | 2 | ||||
| -rw-r--r-- | gui/src/renderer/redux/account/actions.ts | 2 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 1 | ||||
| -rw-r--r-- | mullvad-api/src/device.rs | 7 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/account.rs | 13 | ||||
| -rw-r--r-- | mullvad-daemon/src/device/mod.rs | 19 | ||||
| -rw-r--r-- | mullvad-daemon/src/device/service.rs | 23 | ||||
| -rw-r--r-- | mullvad-daemon/src/lib.rs | 5 | ||||
| -rw-r--r-- | mullvad-management-interface/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-management-interface/proto/management_interface.proto | 5 | ||||
| -rw-r--r-- | mullvad-management-interface/src/types.rs | 19 | ||||
| -rw-r--r-- | mullvad-types/src/device.rs | 6 |
15 files changed, 79 insertions, 29 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 46410061ad..3c1f3afe37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,8 +25,11 @@ Line wrap the file at 100 chars. Th ## [Unreleased] ### Added - Add option to filter relays by ownership in the desktop apps. +- Include creation timestamp for devices in the CLI. ### Changed +- List devices on an account sorted by creation date, oldest to newest, instead of alphabetically. + #### Android - Lowered default MTU to 1280 on Android. diff --git a/Cargo.lock b/Cargo.lock index 6ae8a7d7e8..5f377c35d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1770,6 +1770,7 @@ dependencies = [ name = "mullvad-management-interface" version = "0.1.0" dependencies = [ + "chrono", "err-derive", "futures", "lazy_static", diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceEvent.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceEvent.kt index 3080d7f10a..94499c032a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceEvent.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceEvent.kt @@ -6,6 +6,5 @@ import kotlinx.parcelize.Parcelize @Parcelize data class RemoveDeviceEvent( val accountToken: String, - val removedDevice: Device, val newDevices: ArrayList<Device> ) : Parcelable diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index 166a48c9cb..e704979a40 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -1476,11 +1476,13 @@ function convertFromDeviceRemoval(deviceRemoval: grpcTypes.RemoveDeviceEvent): A } function convertFromDevice(device: grpcTypes.Device): IDevice { + const created = ensureExists(device.getCreated(), "no 'created' field for device").toDate(); const asObject = device.toObject(); return { ...asObject, ports: asObject.portsList.map((port) => port.id), + created: created, }; } diff --git a/gui/src/renderer/redux/account/actions.ts b/gui/src/renderer/redux/account/actions.ts index cfa672a407..594a96f71f 100644 --- a/gui/src/renderer/redux/account/actions.ts +++ b/gui/src/renderer/redux/account/actions.ts @@ -213,7 +213,7 @@ function updateAccountExpiry(expiry?: string): IUpdateAccountExpiryAction { function updateDevices(devices: Array<IDevice>): IUpdateDevicesAction { return { type: 'UPDATE_DEVICES', - devices: devices.sort((a, b) => a.name.localeCompare(b.name)), + devices: devices.sort((a, b) => a.created.getDate() - b.created.getDate()), }; } diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index 6e70c3f9b6..45af1c605e 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -359,6 +359,7 @@ export interface IDevice { id: string; name: string; ports?: Array<string>; + created: Date; } export interface IDeviceRemoval { diff --git a/mullvad-api/src/device.rs b/mullvad-api/src/device.rs index c3cd253826..af7cbd0a8e 100644 --- a/mullvad-api/src/device.rs +++ b/mullvad-api/src/device.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use http::{Method, StatusCode}; use mullvad_types::{ account::AccountToken, @@ -23,6 +24,8 @@ struct DeviceResponse { ipv4_address: ipnetwork::Ipv4Network, ipv6_address: ipnetwork::Ipv6Network, ports: Vec<DevicePort>, + hijack_dns: bool, + created: DateTime<Utc>, } impl DevicesProxy { @@ -71,6 +74,8 @@ impl DevicesProxy { ipv4_address, ipv6_address, ports, + hijack_dns, + created, .. } = response; @@ -80,6 +85,8 @@ impl DevicesProxy { name, pubkey, ports, + hijack_dns, + created, }, mullvad_types::wireguard::AssociatedAddresses { ipv4_address, diff --git a/mullvad-cli/src/cmds/account.rs b/mullvad-cli/src/cmds/account.rs index c6c723c5ce..8432f1da0a 100644 --- a/mullvad-cli/src/cmds/account.rs +++ b/mullvad-cli/src/cmds/account.rs @@ -156,6 +156,10 @@ impl Account { if verbose { println!("Device id : {}", inner_device.id); println!("Device pubkey : {}", inner_device.pubkey); + println!( + "Device created : {}", + inner_device.created.with_timezone(&chrono::Local) + ); for port in inner_device.ports { println!("Device port : {}", port); } @@ -184,7 +188,7 @@ impl Account { async fn list_devices(&self, matches: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let token = self.parse_account_else_current(&mut rpc, matches).await?; - let device_list = rpc + let mut device_list = rpc .list_devices(token) .await .map_err(map_device_error)? @@ -193,6 +197,9 @@ impl Account { let verbose = matches.is_present("verbose"); println!("Devices on the account:"); + device_list + .devices + .sort_unstable_by_key(|dev| dev.created.as_ref().map(|dt| dt.seconds).unwrap_or(0)); for device in device_list.devices { let device = Device::try_from(device.clone()).unwrap(); if verbose { @@ -200,6 +207,10 @@ impl Account { println!("Name : {}", device.pretty_name()); println!("Id : {}", device.id); println!("Public key: {}", device.pubkey); + println!( + "Created : {}", + device.created.with_timezone(&chrono::Local) + ); for port in device.ports { println!("Port : {}", port); } diff --git a/mullvad-daemon/src/device/mod.rs b/mullvad-daemon/src/device/mod.rs index 84fa1afa50..4d420a404a 100644 --- a/mullvad-daemon/src/device/mod.rs +++ b/mullvad-daemon/src/device/mod.rs @@ -157,6 +157,19 @@ pub struct PrivateDevice { pub name: DeviceName, pub wg_data: wireguard::WireguardData, pub ports: Vec<DevicePort>, + // FIXME: Reasonable default to avoid migration code for the field, + // as it was previously missing. + // This attribute may be removed once upgrades from `2022.2-beta1` + // no longer need to be supported. + #[serde(default)] + pub hijack_dns: bool, + // FIXME: Incorrect but reasonable default to avoid migration code + // for the field, as it was previously missing. + // The value is corrected when the device is validated or updated. + // This attribute may be removed once upgrades from `2022.2-beta1` + // no longer need to be supported. + #[serde(default = "Utc::now")] + pub created: DateTime<Utc>, } impl PrivateDevice { @@ -174,6 +187,8 @@ impl PrivateDevice { name: device.name, wg_data, ports: device.ports, + hijack_dns: device.hijack_dns, + created: device.created, }) } @@ -186,6 +201,8 @@ impl PrivateDevice { self.id = device.id; self.ports = device.ports; self.name = device.name; + self.hijack_dns = device.hijack_dns; + self.created = device.created; Ok(()) } } @@ -197,6 +214,8 @@ impl From<PrivateDevice> for Device { ports: device.ports, pubkey: device.wg_data.private_key.public_key(), name: device.name, + hijack_dns: device.hijack_dns, + created: device.created, } } } diff --git a/mullvad-daemon/src/device/service.rs b/mullvad-daemon/src/device/service.rs index f4f147ac96..90a44d5fe1 100644 --- a/mullvad-daemon/src/device/service.rs +++ b/mullvad-daemon/src/device/service.rs @@ -109,27 +109,10 @@ impl DeviceService { &self, account_token: AccountToken, device_id: DeviceId, - ) -> Result<(Device, Vec<Device>), Error> { - let mut devices = self.list_devices(account_token.clone()).await?; - self.remove_device_inner(account_token, device_id.clone()) + ) -> Result<Vec<Device>, Error> { + self.remove_device_inner(account_token.clone(), device_id) .await?; - if let Some(index) = devices.iter().position(|device| device.id == device_id) { - Ok((devices.swap_remove(index), devices)) - } else { - // You would only end up here if the API service successfully removed a device that - // was previously not included in the list returned by it, which should be impossible. - // Just return a bogus device in its place. - log::error!("List did not contain the revoked device"); - Ok(( - Device { - id: device_id, - name: "unknown device".to_string(), - pubkey: talpid_types::net::wireguard::PublicKey::from([0u8; 32]), - ports: vec![], - }, - devices, - )) - } + self.list_devices(account_token).await } async fn remove_device_inner( diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs index fbc27bcc92..b75ad9121c 100644 --- a/mullvad-daemon/src/lib.rs +++ b/mullvad-daemon/src/lib.rs @@ -1393,10 +1393,11 @@ where let result = device_service .remove_device(account_token.clone(), device_id) .await - .map(move |(removed_device, new_devices)| { + .map(move |new_devices| { + // FIXME: We should be able to get away with only returning the removed ID, + // and not have to request the list from the API. event_listener.notify_remove_device_event(RemoveDeviceEvent { account_token, - removed_device, new_devices, }); }); diff --git a/mullvad-management-interface/Cargo.toml b/mullvad-management-interface/Cargo.toml index e6b00a36b1..ca1853855b 100644 --- a/mullvad-management-interface/Cargo.toml +++ b/mullvad-management-interface/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" publish = false [dependencies] +chrono = { version = "0.4.19" } err-derive = "0.3.1" mullvad-types = { path = "../mullvad-types" } mullvad-paths = { path = "../mullvad-paths" } diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index 42a73ca7bd..20d5318a58 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -580,6 +580,8 @@ message Device { string name = 2; bytes pubkey = 3; repeated DevicePort ports = 4; + bool hijack_dns = 5; + google.protobuf.Timestamp created = 6; } message DevicePort { @@ -619,6 +621,5 @@ message DeviceEvent { message RemoveDeviceEvent { string account_token = 1; - Device removed_device = 2; - repeated Device new_device_list = 3; + repeated Device new_device_list = 2; } diff --git a/mullvad-management-interface/src/types.rs b/mullvad-management-interface/src/types.rs index 4785f7221d..54aac8964f 100644 --- a/mullvad-management-interface/src/types.rs +++ b/mullvad-management-interface/src/types.rs @@ -217,6 +217,11 @@ impl From<mullvad_types::device::Device> for Device { name: device.name, pubkey: device.pubkey.as_bytes().to_vec(), ports: device.ports.into_iter().map(DevicePort::from).collect(), + hijack_dns: device.hijack_dns, + created: Some(Timestamp { + seconds: device.created.timestamp(), + nanos: 0, + }), } } } @@ -276,7 +281,6 @@ impl From<mullvad_types::device::RemoveDeviceEvent> for RemoveDeviceEvent { fn from(event: mullvad_types::device::RemoveDeviceEvent) -> Self { RemoveDeviceEvent { account_token: event.account_token, - removed_device: Some(Device::from(event.removed_device)), new_device_list: event.new_devices.into_iter().map(Device::from).collect(), } } @@ -808,6 +812,19 @@ impl TryFrom<Device> for mullvad_types::device::Device { .into_iter() .map(mullvad_types::device::DevicePort::from) .collect(), + hijack_dns: device.hijack_dns, + created: chrono::DateTime::from_utc( + chrono::NaiveDateTime::from_timestamp( + device + .created + .ok_or(FromProtobufTypeError::InvalidArgument( + "missing 'created' field", + ))? + .seconds, + 0, + ), + chrono::Utc, + ), }) } } diff --git a/mullvad-types/src/device.rs b/mullvad-types/src/device.rs index df7ba7bef0..38dd528fd5 100644 --- a/mullvad-types/src/device.rs +++ b/mullvad-types/src/device.rs @@ -1,4 +1,5 @@ use crate::account::AccountToken; +use chrono::{DateTime, Utc}; #[cfg(target_os = "android")] use jnix::IntoJava; use serde::{Deserialize, Serialize}; @@ -21,6 +22,10 @@ pub struct Device { #[cfg_attr(target_os = "android", jnix(map = "|key| *key.as_bytes()"))] pub pubkey: PublicKey, pub ports: Vec<DevicePort>, + #[cfg_attr(target_os = "android", jnix(skip))] + pub hijack_dns: bool, + #[cfg_attr(target_os = "android", jnix(skip))] + pub created: DateTime<Utc>, } impl Eq for Device {} @@ -132,6 +137,5 @@ pub struct DeviceEvent { #[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] pub struct RemoveDeviceEvent { pub account_token: AccountToken, - pub removed_device: Device, pub new_devices: Vec<Device>, } |
