Last active
June 7, 2019 19:11
-
-
Save jonathanpeppers/49ae62c0e377676292f7940be4de5216 to your computer and use it in GitHub Desktop.
Google Play purchase service - HandleActivityResult
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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