Skip to content

Commit 11ff207

Browse files
Expose play purchase API via gRPC
1 parent eced118 commit 11ff207

File tree

5 files changed

+97
-78
lines changed

5 files changed

+97
-78
lines changed

mullvad-daemon/src/management_interface.rs

+54
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,60 @@ impl ManagementService for ManagementServiceImpl {
956956
let blob = self.wait_for_result(rx).await??;
957957
Ok(Response::new(blob))
958958
}
959+
960+
#[cfg(target_os = "android")]
961+
async fn init_play_purchase(
962+
&self,
963+
_request: Request<()>,
964+
) -> ServiceResult<types::PlayPurchasePaymentToken> {
965+
log::debug!("init_play_purchase");
966+
967+
let (tx, rx) = oneshot::channel();
968+
self.send_command_to_daemon(DaemonCommand::InitPlayPurchase(tx))?;
969+
970+
let payment_token = self
971+
.wait_for_result(rx)
972+
.await?
973+
.map(types::PlayPurchasePaymentToken::from)
974+
.map_err(map_daemon_error)??;
975+
976+
Ok(Response::new(payment_token))
977+
}
978+
979+
/// On non-Android platforms, the return value will be useless.
980+
#[cfg(not(target_os = "android"))]
981+
async fn init_play_purchase(
982+
&self,
983+
_: Request<()>,
984+
) -> ServiceResult<types::PlayPurchasePaymentToken> {
985+
log::error!("Called `init_play_purchase` on non-Android platform");
986+
Ok(Response::new(types::PlayPurchasePaymentToken::from(
987+
String::default(),
988+
)))
989+
}
990+
991+
#[cfg(target_os = "android")]
992+
async fn verify_play_purchase(
993+
&self,
994+
request: Request<types::PlayPurchase>,
995+
) -> ServiceResult<()> {
996+
log::debug!("verify_play_purchase");
997+
998+
let (tx, rx) = oneshot::channel();
999+
let play_purchase = mullvad_types::account::PlayPurchase::try_from(config.into_inner())?;
1000+
1001+
self.send_command_to_daemon(DaemonCommand::VerifyPlayPurchase(tx, play_purchase))?;
1002+
1003+
self.wait_for_result(rx).await?.map_err(map_daemon_error)?;
1004+
1005+
Ok(Response::new(()))
1006+
}
1007+
1008+
#[cfg(not(target_os = "android"))]
1009+
async fn verify_play_purchase(&self, _: Request<types::PlayPurchase>) -> ServiceResult<()> {
1010+
log::error!("Called `verify_play_purchase` on non-Android platform");
1011+
Ok(Response::new(()))
1012+
}
9591013
}
9601014

9611015
impl ManagementServiceImpl {

mullvad-jni/src/daemon_interface.rs

+1-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use futures::{channel::oneshot, executor::block_on};
22
use mullvad_daemon::{device, settings::patch, DaemonCommand, DaemonCommandSender};
33
use mullvad_types::{
4-
account::{AccountData, AccountToken, PlayPurchase, VoucherSubmission},
4+
account::{AccountData, AccountToken, VoucherSubmission},
55
custom_list::CustomList,
66
device::{Device, DeviceState},
77
relay_constraints::{ObfuscationSettings, RelayOverride, RelaySettings},
@@ -301,26 +301,6 @@ impl DaemonInterface {
301301
.map_err(Error::from)
302302
}
303303

304-
pub fn init_play_purchase(&self) -> Result<String> {
305-
let (tx, rx) = oneshot::channel();
306-
307-
self.send_command(DaemonCommand::InitPlayPurchase(tx))?;
308-
309-
block_on(rx)
310-
.map_err(|_| Error::NoResponse)?
311-
.map_err(Error::from)
312-
}
313-
314-
pub fn verify_play_purchase(&self, play_purchase: PlayPurchase) -> Result<()> {
315-
let (tx, rx) = oneshot::channel();
316-
317-
self.send_command(DaemonCommand::VerifyPlayPurchase(tx, play_purchase))?;
318-
319-
block_on(rx)
320-
.map_err(|_| Error::NoResponse)?
321-
.map_err(Error::from)
322-
}
323-
324304
pub fn set_relay_settings(&self, update: RelaySettings) -> Result<()> {
325305
let (tx, rx) = oneshot::channel();
326306

mullvad-jni/src/lib.rs

+1-57
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use mullvad_daemon::{
2323
settings::patch::Error as PatchError, version, Daemon, DaemonCommandChannel,
2424
};
2525
use mullvad_types::{
26-
account::{AccountData, PlayPurchase, VoucherSubmission},
26+
account::{AccountData, VoucherSubmission},
2727
custom_list::CustomList,
2828
relay_constraints::RelayOverride,
2929
settings::DnsOptions,
@@ -1301,62 +1301,6 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_submitV
13011301
result.into_java(&env).forget()
13021302
}
13031303

1304-
#[no_mangle]
1305-
#[allow(non_snake_case)]
1306-
pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_initPlayPurchase<'env>(
1307-
env: JNIEnv<'env>,
1308-
_: JObject<'_>,
1309-
daemon_interface_address: jlong,
1310-
) -> JObject<'env> {
1311-
let env = JnixEnv::from(env);
1312-
1313-
let result =
1314-
// SAFETY: The address points to an instance valid for the duration of this function call
1315-
if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } {
1316-
let raw_result = daemon_interface.init_play_purchase();
1317-
1318-
if let Err(ref error) = &raw_result {
1319-
log_request_error("init google play purchase", error);
1320-
}
1321-
1322-
PlayPurchaseInitResult::from(raw_result)
1323-
} else {
1324-
PlayPurchaseInitResult::Error(PlayPurchaseInitError::OtherError)
1325-
};
1326-
1327-
result.into_java(&env).forget()
1328-
}
1329-
1330-
#[no_mangle]
1331-
#[allow(non_snake_case)]
1332-
pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_verifyPlayPurchase<
1333-
'env,
1334-
>(
1335-
env: JNIEnv<'env>,
1336-
_: JObject<'_>,
1337-
daemon_interface_address: jlong,
1338-
play_purchase: JObject<'_>,
1339-
) -> JObject<'env> {
1340-
let env = JnixEnv::from(env);
1341-
1342-
let result =
1343-
// SAFETY: The address points to an instance valid for the duration of this function call
1344-
if let Some(daemon_interface) = unsafe { get_daemon_interface(daemon_interface_address) } {
1345-
let play_purchase = PlayPurchase::from_java(&env, play_purchase);
1346-
let raw_result = daemon_interface.verify_play_purchase(play_purchase);
1347-
1348-
if let Err(ref error) = &raw_result {
1349-
log_request_error("verify google play purchase", error);
1350-
}
1351-
1352-
PlayPurchaseVerifyResult::from(raw_result)
1353-
} else {
1354-
PlayPurchaseVerifyResult::Error(PlayPurchaseVerifyError::OtherError)
1355-
};
1356-
1357-
result.into_java(&env).forget()
1358-
}
1359-
13601304
#[no_mangle]
13611305
#[allow(non_snake_case)]
13621306
pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_setRelaySettings(

mullvad-management-interface/proto/management_interface.proto

+12
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ service ManagementService {
9999
rpc SetSplitTunnelState(google.protobuf.BoolValue) returns (google.protobuf.Empty) {}
100100
rpc GetExcludedProcesses(google.protobuf.Empty) returns (ExcludedProcessList) {}
101101

102+
// Play payment (Android)
103+
rpc InitPlayPurchase(google.protobuf.Empty) returns (PlayPurchasePaymentToken) {}
104+
rpc VerifyPlayPurchase(PlayPurchase) returns (google.protobuf.Empty) {}
105+
102106
// Notify the split tunnel monitor that a volume was mounted or dismounted
103107
// (Windows).
104108
rpc CheckVolumes(google.protobuf.Empty) returns (google.protobuf.Empty) {}
@@ -701,3 +705,11 @@ message RemoveDeviceEvent {
701705
string account_token = 1;
702706
repeated Device new_device_list = 2;
703707
}
708+
709+
message PlayPurchase {
710+
string product_id = 1;
711+
PlayPurchasePaymentToken purchase_token = 2;
712+
}
713+
714+
message PlayPurchasePaymentToken { string token = 1; }
715+

mullvad-management-interface/src/types/conversions/account.rs

+29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::types;
22
use chrono::TimeZone;
33
use mullvad_types::account::{AccountData, VoucherSubmission};
4+
#[cfg(target_os = "android")]
5+
use mullvad_types::account::{PlayPurchase, PlayPurchasePaymentToken};
46

57
use super::FromProtobufTypeError;
68

@@ -62,3 +64,30 @@ impl TryFrom<types::AccountData> for AccountData {
6264
})
6365
}
6466
}
67+
68+
#[cfg(target_os = "android")]
69+
impl TryFrom<types::PlayPurchase> for PlayPurchase {
70+
type Error = FromProtobufTypeError;
71+
72+
fn try_from(value: types::PlayPurchase) -> Result<Self, Self::Error> {
73+
let product_id = value.product_id;
74+
let purchase_token = value
75+
.purchase_token
76+
.ok_or(FromProtobufTypeError::InvalidArgument(
77+
"Missing purchase token",
78+
))?
79+
.token;
80+
81+
Ok(Self {
82+
product_id,
83+
purchase_token,
84+
})
85+
}
86+
}
87+
88+
#[cfg(target_os = "android")]
89+
impl From<PlayPurchasePaymentToken> for types::PlayPurchasePaymentToken {
90+
fn from(value: PlayPurchasePaymentToken) -> Self {
91+
Self { token: value }
92+
}
93+
}

0 commit comments

Comments
 (0)