Skip to content

Commit

Permalink
Fetch account ID from API
Browse files Browse the repository at this point in the history
  • Loading branch information
dlon committed Dec 29, 2023
1 parent 2d1e643 commit cf1a16c
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 35 deletions.
15 changes: 4 additions & 11 deletions mullvad-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#![deny(rust_2018_idioms)]

use chrono::{offset::Utc, DateTime};
#[cfg(target_os = "android")]
use futures::channel::mpsc;
use futures::Stream;
use hyper::Method;
#[cfg(target_os = "android")]
use mullvad_types::account::{PlayPurchase, PlayPurchasePaymentToken};
use mullvad_types::{
account::{AccountToken, VoucherSubmission},
account::{AccountData, AccountToken, VoucherSubmission},
version::AppVersion,
};
use proxy::ApiConnectionMode;
Expand Down Expand Up @@ -382,15 +381,10 @@ impl AccountsProxy {
Self { handle }
}

pub fn get_expiry(
pub fn get_data(
&self,
account: AccountToken,
) -> impl Future<Output = Result<DateTime<Utc>, rest::Error>> {
#[derive(serde::Deserialize)]
struct AccountExpiryResponse {
expiry: DateTime<Utc>,
}

) -> impl Future<Output = Result<AccountData, rest::Error>> {
let service = self.handle.service.clone();
let factory = self.handle.factory.clone();
async move {
Expand All @@ -399,8 +393,7 @@ impl AccountsProxy {
.expected_status(&[StatusCode::OK])
.account(account)?;
let response = service.request(request).await?;
let account: AccountExpiryResponse = response.deserialize().await?;
Ok(account.expiry)
response.deserialize().await
}
}

Expand Down
11 changes: 9 additions & 2 deletions mullvad-daemon/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,11 +1100,18 @@ impl AccountManager {
Ok(self.fetch_device_config(old_config))
}

fn expiry_call(&self) -> Result<impl Future<Output = Result<DateTime<Utc>, Error>>, Error> {
fn expiry_call(
&self,
) -> Result<impl Future<Output = Result<chrono::DateTime<Utc>, Error>>, Error> {
let old_config = self.data.device().ok_or(Error::NoDevice)?;
let account_token = old_config.account_token.clone();
let account_service = self.account_service.clone();
Ok(async move { account_service.check_expiry_2(account_token).await })
Ok(async move {
account_service
.get_data_2(account_token)
.await
.map(|data| data.expiry)
})
}

fn needs_validation(&mut self) -> bool {
Expand Down
26 changes: 13 additions & 13 deletions mullvad-daemon/src/device/service.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::{future::Future, time::Duration};

use chrono::{DateTime, Utc};
use chrono::Utc;
use futures::future::{abortable, AbortHandle};
#[cfg(target_os = "android")]
use mullvad_types::account::{PlayPurchase, PlayPurchasePaymentToken};
use mullvad_types::{
account::{AccountToken, VoucherSubmission},
account::{AccountData, AccountToken, VoucherSubmission},
device::{Device, DeviceId},
wireguard::WireguardData,
};
Expand Down Expand Up @@ -284,23 +284,23 @@ impl AccountService {
)
}

pub async fn check_expiry(&self, token: AccountToken) -> Result<DateTime<Utc>, rest::Error> {
pub async fn get_data(&self, token: AccountToken) -> Result<AccountData, rest::Error> {
let proxy = self.proxy.clone();
let api_handle = self.api_availability.clone();
let result = retry_future(
move || proxy.get_expiry(token.clone()),
move || proxy.get_data(token.clone()),
move |result| should_retry(result, &api_handle),
RETRY_ACTION_STRATEGY,
)
.await;
if handle_expiry_result_inner(&result, &self.api_availability) {
if handle_account_data_result(&result, &self.api_availability) {
self.initial_check_abort_handle.abort();
}
result
}

pub async fn check_expiry_2(&self, token: AccountToken) -> Result<DateTime<Utc>, Error> {
self.check_expiry(token).await.map_err(map_rest_error)
pub async fn get_data_2(&self, token: AccountToken) -> Result<AccountData, Error> {
self.get_data(token).await.map_err(map_rest_error)
}

pub async fn submit_voucher(
Expand Down Expand Up @@ -385,9 +385,9 @@ pub fn spawn_account_service(
};

let future_generator = move || {
let expiry_fut = api_availability.when_online(accounts_proxy.get_expiry(token.clone()));
let expiry_fut = api_availability.when_online(accounts_proxy.get_data(token.clone()));
let api_availability_copy = api_availability.clone();
async move { handle_expiry_result_inner(&expiry_fut.await, &api_availability_copy) }
async move { handle_account_data_result(&expiry_fut.await, &api_availability_copy) }
};
let should_retry = move |state_was_updated: &bool| -> bool { !*state_was_updated };
retry_future(future_generator, should_retry, RETRY_BACKOFF_STRATEGY).await;
Expand All @@ -401,16 +401,16 @@ pub fn spawn_account_service(
}
}

fn handle_expiry_result_inner(
result: &Result<chrono::DateTime<chrono::Utc>, rest::Error>,
fn handle_account_data_result(
result: &Result<AccountData, rest::Error>,
api_availability: &ApiAvailabilityHandle,
) -> bool {
match result {
Ok(_expiry) if *_expiry >= chrono::Utc::now() => {
Ok(_data) if _data.expiry >= chrono::Utc::now() => {
api_availability.resume_background();
true
}
Ok(_expiry) => {
Ok(_data) => {
api_availability.pause_background();
true
}
Expand Down
8 changes: 2 additions & 6 deletions mullvad-daemon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1445,12 +1445,8 @@ where
) {
let account = self.account_manager.account_service.clone();
tokio::spawn(async move {
let result = account.check_expiry(account_token).await;
Self::oneshot_send(
tx,
result.map(|expiry| AccountData { expiry }),
"account data",
);
let result = account.get_data(account_token).await;
Self::oneshot_send(tx, result, "account data");
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ service ManagementService {

message UUID { string value = 1; }

message AccountData { google.protobuf.Timestamp expiry = 1; }
message AccountData {
string id = 1;
google.protobuf.Timestamp expiry = 2;
}

message AccountHistory { google.protobuf.StringValue token = 1; }

Expand Down
2 changes: 2 additions & 0 deletions mullvad-management-interface/src/types/conversions/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl TryFrom<types::VoucherSubmission> for VoucherSubmission {
impl From<AccountData> for types::AccountData {
fn from(data: AccountData) -> Self {
types::AccountData {
id: data.id,
expiry: Some(types::Timestamp {
seconds: data.expiry.timestamp(),
nanos: 0,
Expand All @@ -56,6 +57,7 @@ impl TryFrom<types::AccountData> for AccountData {
chrono::NaiveDateTime::from_timestamp_opt(expiry.seconds, expiry.nanos as u32).unwrap();

Ok(AccountData {
id: data.id,
expiry: chrono::Utc.from_utc_datetime(&ndt),
})
}
Expand Down
9 changes: 7 additions & 2 deletions mullvad-types/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ use chrono::{offset::Utc, DateTime};
use jnix::{FromJava, IntoJava};
use serde::{Deserialize, Serialize};

/// Identifier used to identify a Mullvad account.
/// Account identifier used for authentication.
pub type AccountToken = String;

/// Identifier used to authenticate a Mullvad account.
/// Temporary authorization token derived from a Mullvad account.
pub type AccessToken = String;

/// Account identifier (not used for authentication).
pub type AccountId = String;

/// The payment token returned by initiating a google play purchase.
/// In the API this is called the `obfuscated_id`.
#[cfg(target_os = "android")]
Expand All @@ -19,6 +22,8 @@ pub type PlayPurchasePaymentToken = String;
#[cfg_attr(target_os = "android", derive(IntoJava))]
#[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))]
pub struct AccountData {
#[cfg_attr(target_os = "android", jnix(skip))]
pub id: AccountId,
#[cfg_attr(target_os = "android", jnix(map = "|expiry| expiry.to_string()"))]
pub expiry: DateTime<Utc>,
}
Expand Down

0 comments on commit cf1a16c

Please sign in to comment.