public static List<VerifiedPurchase> VerifyPurchase(string signedData, string signature)
{
if (signedData == null)
{
Log.Error(TAG, "data is null");
return null;
}
if (Consts.DEBUG)
{
Log.Info(TAG, "signedData: " + signedData);
}
bool verified = false;
if (!TextUtils.IsEmpty(signature))
{
/// <summary>
/// Compute your public key (that you got from the Android Market publisher site).
///
/// Instead of just storing the entire literal string here embedded in the
/// program, construct the key at runtime from pieces or
/// use bit manipulation (for example, XOR with some other string) to hide
/// the actual key. The key itself is not secret information, but we don't
/// want to make it easy for an adversary to replace the public key with one
/// of their own and then fake messages from the server.
///
/// Generally, encryption keys / passwords should only be kept in memory
/// long enough to perform the operation they need to perform.
/// </summary>
string base64EncodedPublicKey = "<Your Key Here>";
IPublicKey key = Security.GeneratePublicKey(base64EncodedPublicKey);
verified = Security.Verify(key, signedData, signature);
if (!verified)
{
Log.Warn(TAG, "signature does not match data.");
return null;
}
}
JObject jObject;
JArray jTransactionsArray = null;
int numTransactions = 0;
long nonce = 0L;
try
{
JObject json = JObject.Parse(signedData);
// The nonce might be null if the user backed out of the buy page.
nonce = (long)json.SelectToken("nonce");
jTransactionsArray = (JArray)json.SelectToken("orders");
if (jTransactionsArray != null)
{
numTransactions = jTransactionsArray.Count;
}
}
catch (JsonSerializationException e)
{
return null;
}
if (!Security.IsNonceKnown(nonce))
{
Log.Warn(TAG, "Nonce not found: " + nonce);
return null;
}
List<VerifiedPurchase> purchases = new List<VerifiedPurchase>();
try
{
for (int i = 0; i < numTransactions; i++)
{
JObject jElement = (JObject)jTransactionsArray[i];
int response = (int)jElement.SelectToken("purchaseState");
Consts.PurchaseState purchaseState = (Consts.PurchaseState)response;
string productId = (string)jElement.SelectToken("productId");
string packageName = (string)jElement.SelectToken("packageName");
long purchaseTime = (long)jElement.SelectToken("purchaseTime");
string orderId = (string)jElement.SelectToken("orderId");
string notifyId = null;
if (jElement.SelectToken("notificationId") != null)
{
notifyId = (string)jElement.SelectToken("notificationId");
}
string developerPayload = (string)jElement.SelectToken("developerPayload");
// If the purchase state is PURCHASED, then we require a
// verified nonce.
if (purchaseState == Consts.PurchaseState.PURCHASED && !verified)
{
continue;
}
purchases.Add(new VerifiedPurchase(purchaseState, notifyId, productId, orderId, purchaseTime, developerPayload));
}
}
catch (JsonSerializationException e)
{
Log.Error(TAG, "JSON exception: ", e);
return null;
}
RemoveNonce(nonce);
return purchases;
}