Skip to content

Instantly share code, notes, and snippets.

@jonathanpeppers
Last active June 7, 2019 19:11
Show Gist options
  • Save jonathanpeppers/49ae62c0e377676292f7940be4de5216 to your computer and use it in GitHub Desktop.
Save jonathanpeppers/49ae62c0e377676292f7940be4de5216 to your computer and use it in GitHub Desktop.
Google Play purchase service - HandleActivityResult
private TaskCompletionSource<Order> _purchaseSource;
private IPublicKey _publicKey;
//NOTE: get this key from the Google Play dev console, under Development Tools | Services & APIs | Licensing & in-app billing
public string PublicKey { get; set; }
//Order details class, parsed from JSON
private sealed class Order
{
public string PackageName { get; set; }
public string OrderId { get; set; }
public string ProductId { get; set; }
public string DeveloperPayload { get; set; }
public long PurchaseTime { get; set; }
public int PurchaseState { get; set; }
public string PurchaseToken { get; set; }
public byte[] Signature { get; set; }
}
public bool HandleActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == BillingConstants.PurchaseRequestCode)
{
var source = _purchaseSource;
if (source != null)
{
try
{
int responseCode = data.GetIntExtra(BillingConstants.ResponseCode, BillingConstants.ResultOk);
if (responseCode != BillingConstants.ResultOk)
{
source.TrySetException(new Exception($"OnActivityResult {BillingConstants.ResponseCode} failed: {responseCode}"));
return true;
}
if (resultCode != Result.Ok)
{
source.TrySetException(new Exception($"OnActivityResult {nameof(resultCode)} failed: {resultCode}"));
return true;
}
string orderJson = data.GetStringExtra(BillingConstants.InAppPurchaseData);
if (string.IsNullOrEmpty(orderJson))
{
source.TrySetException(new Exception(BillingConstants.InAppPurchaseData + " not found!"));
return true;
}
string signature = data.GetStringExtra(BillingConstants.InAppDataSignature);
if (string.IsNullOrEmpty(signature))
{
source.TrySetException(new Exception(BillingConstants.InAppDataSignature + " not found!"));
return true;
}
var order = JsonConvert.DeserializeObject<Order>(orderJson);
order.Signature = Convert.FromBase64String(signature);
if (IsSignatureValid(order, orderJson))
{
source.TrySetResult(order);
}
else
{
source.TrySetException(new Exception("Signature not valid!"));
}
}
catch (Exception exc)
{
source.TrySetException(exc);
return true;
}
}
return true;
}
return false;
}
private bool IsSignatureValid(Order order, string orderJson)
{
if (string.IsNullOrEmpty(PublicKey))
throw new Exception("PublicKey not set!");
if (_publicKey == null)
{
var bytes = Convert.FromBase64String(PublicKey);
var keyFactory = KeyFactory.GetInstance("RSA");
_publicKey = keyFactory.GeneratePublic(new X509EncodedKeySpec(bytes));
}
var signature = Signature.GetInstance("SHA1withRSA");
signature.InitVerify(_publicKey);
signature.Update(Encoding.Default.GetBytes(orderJson));
return signature.Verify(order.Signature);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment