diff --git a/app/src/main/java/eu/faircode/email/ActivityBilling.java b/app/src/main/java/eu/faircode/email/ActivityBilling.java index 8266f60e68..36d515cbcc 100644 --- a/app/src/main/java/eu/faircode/email/ActivityBilling.java +++ b/app/src/main/java/eu/faircode/email/ActivityBilling.java @@ -29,6 +29,7 @@ import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.provider.Settings; +import android.util.Base64; import android.util.Log; import com.android.billingclient.api.BillingClient; @@ -38,7 +39,11 @@ import com.android.billingclient.api.Purchase; import com.android.billingclient.api.PurchasesUpdatedListener; import com.google.android.material.snackbar.Snackbar; +import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.X509EncodedKeySpec; import java.util.List; import androidx.annotation.Nullable; @@ -213,15 +218,34 @@ abstract class ActivityBilling extends ActivityBase implements PurchasesUpdatedL if (purchases != null) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = prefs.edit(); + if (prefs.getBoolean("play_store", true)) editor.remove("pro"); - for (Purchase purchase : purchases) { - Log.i(Helper.TAG, "IAB SKU=" + purchase.getSku()); - if ((BuildConfig.APPLICATION_ID + ".pro").equals(purchase.getSku())) { - editor.putBoolean("pro", true); - Log.i(Helper.TAG, "IAB pro features activated"); + + for (Purchase purchase : purchases) + try { + Log.i(Helper.TAG, "IAB SKU=" + purchase.getSku()); + + byte[] decodedKey = Base64.decode(getString(R.string.public_key), Base64.DEFAULT); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); + Signature sig = Signature.getInstance("SHA1withRSA"); + sig.initVerify(publicKey); + sig.update(purchase.getOriginalJson().getBytes()); + if (sig.verify(Base64.decode(purchase.getSignature(), Base64.DEFAULT))) { + if ((BuildConfig.APPLICATION_ID + ".pro").equals(purchase.getSku())) { + editor.putBoolean("pro", true); + Log.i(Helper.TAG, "IAB pro features activated"); + } + } else { + Log.w(Helper.TAG, "Invalid signature"); + Snackbar.make(getVisibleView(), R.string.title_pro_invalid, Snackbar.LENGTH_LONG).show(); + } + } catch (Throwable ex) { + Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + Snackbar.make(getVisibleView(), ex.getMessage(), Snackbar.LENGTH_LONG).show(); } - } + editor.apply(); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d15a66a5a5..ad5bc3a55d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -451,4 +451,5 @@ 17BA15C1AF55D925F98B99CEA4375D4CDF4C174B + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtFbxEbzL8u5accPGgBw/XdyiSS5BBE6ZQ9ELpKyJ/OQN+kdYniCAOw3lsQ/GuJScy4Y2HobqbBgLL8GLHG+Yu2EHC9dLjA3v2Mc25vvnfn86BsrpQvz1poN2n+roTBdq09FWbtebJ8m0hDBVmtfRi7RhTKIL4No3kodLhksdnucKjcFheubebWKgpmvbmw7NwuELhaZmyhw8WTtnQ4rZPMhjY1JJZgzwNExXgD7zzg4pJPkuQlfkuRkkvBpHpi3C7VDnYjrBlLHngI4wv3wxQBVwJqlvAT9PmX8dOVnTsWWdJdLQBZVWphuqVY54kjBIovN+o8w03WjsV9QiOQq+XwIDAQAB