Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Google Play payment API to gRPC #6169

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions mullvad-daemon/src/management_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,60 @@ impl ManagementService for ManagementServiceImpl {
let blob = self.wait_for_result(rx).await??;
Ok(Response::new(blob))
}

#[cfg(target_os = "android")]
async fn init_play_purchase(
&self,
_request: Request<()>,
) -> ServiceResult<types::PlayPurchasePaymentToken> {
log::debug!("init_play_purchase");

let (tx, rx) = oneshot::channel();
self.send_command_to_daemon(DaemonCommand::InitPlayPurchase(tx))?;

let payment_token = self
.wait_for_result(rx)
.await?
.map(types::PlayPurchasePaymentToken::from)
.map_err(map_daemon_error)?;

Ok(Response::new(payment_token))
}

/// On non-Android platforms, the return value will be useless.
#[cfg(not(target_os = "android"))]
async fn init_play_purchase(
&self,
_: Request<()>,
) -> ServiceResult<types::PlayPurchasePaymentToken> {
log::error!("Called `init_play_purchase` on non-Android platform");
Ok(Response::new(types::PlayPurchasePaymentToken {
token: String::default(),
}))
}

#[cfg(target_os = "android")]
async fn verify_play_purchase(
&self,
request: Request<types::PlayPurchase>,
) -> ServiceResult<()> {
log::debug!("verify_play_purchase");

let (tx, rx) = oneshot::channel();
let play_purchase = mullvad_types::account::PlayPurchase::try_from(request.into_inner())?;

self.send_command_to_daemon(DaemonCommand::VerifyPlayPurchase(tx, play_purchase))?;

self.wait_for_result(rx).await?.map_err(map_daemon_error)?;

Ok(Response::new(()))
}

#[cfg(not(target_os = "android"))]
async fn verify_play_purchase(&self, _: Request<types::PlayPurchase>) -> ServiceResult<()> {
log::error!("Called `verify_play_purchase` on non-Android platform");
Ok(Response::new(()))
}
}

impl ManagementServiceImpl {
Expand Down
2 changes: 1 addition & 1 deletion mullvad-jni/src/daemon_interface.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use futures::{channel::oneshot, executor::block_on};
use mullvad_daemon::{device, DaemonCommand, DaemonCommandSender};
use mullvad_types::{
account::{AccountData, AccountToken, PlayPurchase, VoucherSubmission},
account::{AccountData, AccountToken, VoucherSubmission},
custom_list::CustomList,
device::{Device, DeviceState},
relay_constraints::{ObfuscationSettings, RelaySettings},
Expand Down
20 changes: 12 additions & 8 deletions mullvad-jni/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod is_null;
mod problem_report;
mod talpid_vpn_service;

use crate::{daemon_interface::DaemonInterface};
use crate::daemon_interface::DaemonInterface;
use jnix::{
jni::{
objects::{GlobalRef, JObject, JString, JValue},
Expand All @@ -18,11 +18,11 @@ use jnix::{
};
use mullvad_api::{rest::Error as RestError, StatusCode};
use mullvad_daemon::{
cleanup_old_rpc_socket, device, exception_logging, logging, runtime::new_multi_thread, version, Daemon,
DaemonCommandChannel,
cleanup_old_rpc_socket, device, exception_logging, logging, runtime::new_multi_thread, version,
Daemon, DaemonCommandChannel,
};
use mullvad_types::{
account::{AccountData, PlayPurchase, VoucherSubmission},
account::{AccountData, VoucherSubmission},
custom_list::CustomList,
settings::DnsOptions,
};
Expand Down Expand Up @@ -276,7 +276,7 @@ fn spawn_daemon(
command_channel: DaemonCommandChannel,
android_context: AndroidContext,
) -> Result<(), Error> {
// let listener = JniEventListener::spawn(env, this).map_err(Error::SpawnJniEventListener)?;
// let listener = JniEventListener::spawn(env, this).map_err(Error::SpawnJniEventListener)?;
let daemon_object = env
.new_global_ref(*this)
.map_err(Error::CreateGlobalReference)?;
Expand Down Expand Up @@ -307,7 +307,9 @@ fn spawn_daemon(

runtime.block_on(cleanup_old_rpc_socket());

let event_listener = match runtime.block_on(async {spawn_management_interface(command_channel.sender()) }) {
let event_listener = match runtime
.block_on(async { spawn_management_interface(command_channel.sender()) })
{
Ok(event_listener) => event_listener,
Err(error) => {
let _ = tx.send(Err(error));
Expand Down Expand Up @@ -356,7 +358,10 @@ fn spawn_management_interface(
) -> Result<ManagementInterfaceEventBroadcaster, Error> {
let (socket_path, event_broadcaster) = ManagementInterfaceServer::start(command_sender)
.map_err(|error| {
log::error!("{}", error.display_chain_with_msg("Unable to start management interface server"));
log::error!(
"{}",
error.display_chain_with_msg("Unable to start management interface server")
);
Error::SpawnManagementInterface(error)
})?;

Expand Down Expand Up @@ -493,7 +498,6 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_service_MullvadDaemon_shutdow
}
}


fn log_request_error(request: &str, error: &daemon_interface::Error) {
match error {
daemon_interface::Error::Api(RestError::Aborted) => {
Expand Down
11 changes: 11 additions & 0 deletions mullvad-management-interface/proto/management_interface.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ service ManagementService {
rpc SetSplitTunnelState(google.protobuf.BoolValue) returns (google.protobuf.Empty) {}
rpc GetExcludedProcesses(google.protobuf.Empty) returns (ExcludedProcessList) {}

// Play payment (Android)
rpc InitPlayPurchase(google.protobuf.Empty) returns (PlayPurchasePaymentToken) {}
rpc VerifyPlayPurchase(PlayPurchase) returns (google.protobuf.Empty) {}

// Notify the split tunnel monitor that a volume was mounted or dismounted
// (Windows).
rpc CheckVolumes(google.protobuf.Empty) returns (google.protobuf.Empty) {}
Expand Down Expand Up @@ -701,3 +705,10 @@ message RemoveDeviceEvent {
string account_token = 1;
repeated Device new_device_list = 2;
}

message PlayPurchase {
string product_id = 1;
PlayPurchasePaymentToken purchase_token = 2;
}

message PlayPurchasePaymentToken { string token = 1; }
29 changes: 29 additions & 0 deletions mullvad-management-interface/src/types/conversions/account.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::types;
use chrono::TimeZone;
use mullvad_types::account::{AccountData, VoucherSubmission};
#[cfg(target_os = "android")]
use mullvad_types::account::{PlayPurchase, PlayPurchasePaymentToken};

use super::FromProtobufTypeError;

Expand Down Expand Up @@ -62,3 +64,30 @@ impl TryFrom<types::AccountData> for AccountData {
})
}
}

#[cfg(target_os = "android")]
impl TryFrom<types::PlayPurchase> for PlayPurchase {
type Error = FromProtobufTypeError;

fn try_from(value: types::PlayPurchase) -> Result<Self, Self::Error> {
let product_id = value.product_id;
let purchase_token = value
.purchase_token
.ok_or(FromProtobufTypeError::InvalidArgument(
"Missing purchase token",
))?
.token;

Ok(Self {
product_id,
purchase_token,
})
}
}

#[cfg(target_os = "android")]
impl From<PlayPurchasePaymentToken> for types::PlayPurchasePaymentToken {
fn from(token: PlayPurchasePaymentToken) -> Self {
Self { token }
}
}
Loading