Files
Daniel Elliott c080f0d97f Add Discord community version (64-bit only)
- Added realracing3-community.apk (71.57 MB)
- Removed 32-bit support (armeabi-v7a)
- Only includes arm64-v8a libraries
- Decompiled source code included
- Added README-community.md with analysis
2026-02-18 15:48:36 -08:00

162 lines
6.6 KiB
Java

package com.firemonkeys.cloudcellapi;
import android.text.TextUtils;
import com.facebook.gamingservices.cloudgaming.internal.SDKConstants;
import com.firemonkeys.cloudcellapi.Consts;
import com.firemonkeys.cloudcellapi.util.Base64;
import com.firemonkeys.cloudcellapi.util.Base64DecoderException;
import com.unity3d.ads.core.domain.HandleInvocationsFromAdViewer;
import com.unity3d.ads.metadata.InAppPurchaseMetaData;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.HashSet;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/* loaded from: classes2.dex */
public class Security {
private static final String CLASSNAME = "Security";
private static final String KEY_FACTORY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
private static final SecureRandom RANDOM = new SecureRandom();
private static HashSet<Long> sKnownNonces = new HashSet<>();
public static class VerifiedPurchase {
public String developerPayload;
public String notificationId;
public String orderId;
public String packageName;
public String productId;
public Consts.PurchaseState purchaseState;
public long purchaseTime;
public VerifiedPurchase(Consts.PurchaseState purchaseState, String str, String str2, String str3, String str4, long j, String str5) {
this.purchaseState = purchaseState;
this.notificationId = str;
this.productId = str2;
this.orderId = str3;
this.packageName = str4;
this.purchaseTime = j;
this.developerPayload = str5;
}
}
public static long generateNonce() {
long nextLong = RANDOM.nextLong();
sKnownNonces.add(Long.valueOf(nextLong));
return nextLong;
}
public static void removeNonce(long j) {
sKnownNonces.remove(Long.valueOf(j));
}
public static boolean isNonceKnown(long j) {
return sKnownNonces.contains(Long.valueOf(j));
}
public static ArrayList<VerifiedPurchase> getVerifiedPurchaseList(String str, String str2, String str3) {
boolean z;
if (str == null) {
Logging.CC_ERROR(CLASSNAME, "public key is null");
return null;
}
if (str2 == null) {
Logging.CC_ERROR(CLASSNAME, "data is null");
return null;
}
Logging.CC_INFO(CLASSNAME, "signedData: " + str2);
if (TextUtils.isEmpty(str3)) {
z = false;
} else {
z = verify(generatePublicKey(str), str2, str3);
if (!z) {
Logging.CC_WARNING(CLASSNAME, "signature does not match data.");
return null;
}
}
try {
JSONObject jSONObject = new JSONObject(str2);
long optLong = jSONObject.optLong("nonce");
JSONArray optJSONArray = jSONObject.optJSONArray("orders");
int length = optJSONArray != null ? optJSONArray.length() : 0;
if (!isNonceKnown(optLong)) {
Logging.CC_WARNING(CLASSNAME, "Nonce not found: " + optLong);
return null;
}
ArrayList<VerifiedPurchase> arrayList = new ArrayList<>();
for (int i = 0; i < length; i++) {
try {
JSONObject jSONObject2 = optJSONArray.getJSONObject(i);
Consts.PurchaseState valueOf = Consts.PurchaseState.valueOf(jSONObject2.getInt("purchaseState"));
String string = jSONObject2.getString(InAppPurchaseMetaData.KEY_PRODUCT_ID);
String string2 = jSONObject2.getString(HandleInvocationsFromAdViewer.KEY_PACKAGE_NAME);
long j = jSONObject2.getLong("purchaseTime");
String optString = jSONObject2.optString("orderId", "");
String string3 = jSONObject2.has("notificationId") ? jSONObject2.getString("notificationId") : null;
String optString2 = jSONObject2.optString(SDKConstants.PARAM_DEVELOPER_PAYLOAD, null);
if (valueOf != Consts.PurchaseState.PURCHASED || z) {
arrayList.add(new VerifiedPurchase(valueOf, string3, string, optString, string2, j, optString2));
}
} catch (JSONException e) {
Logging.CC_ERROR(CLASSNAME, "JSON exception: " + e.toString());
return null;
}
}
removeNonce(optLong);
return arrayList;
} catch (JSONException unused) {
return null;
}
}
public static PublicKey generatePublicKey(String str) {
try {
return KeyFactory.getInstance(KEY_FACTORY_ALGORITHM).generatePublic(new X509EncodedKeySpec(Base64.decode(str)));
} catch (Base64DecoderException e) {
Logging.CC_ERROR(CLASSNAME, "Base64 decoding failed.");
throw new IllegalArgumentException(e);
} catch (NoSuchAlgorithmException e2) {
throw new RuntimeException(e2);
} catch (InvalidKeySpecException e3) {
Logging.CC_ERROR(CLASSNAME, "Invalid key specification.");
throw new IllegalArgumentException(e3);
}
}
public static boolean verify(PublicKey publicKey, String str, String str2) {
Logging.CC_INFO(CLASSNAME, "signature: " + str2);
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicKey);
signature.update(str.getBytes());
if (signature.verify(Base64.decode(str2))) {
return true;
}
Logging.CC_ERROR(CLASSNAME, "Signature verification failed.");
return false;
} catch (Base64DecoderException unused) {
Logging.CC_ERROR(CLASSNAME, "Base64 decoding failed.");
return false;
} catch (InvalidKeyException unused2) {
Logging.CC_ERROR(CLASSNAME, "Invalid key specification.");
return false;
} catch (NoSuchAlgorithmException unused3) {
Logging.CC_ERROR(CLASSNAME, "NoSuchAlgorithmException.");
return false;
} catch (SignatureException unused4) {
Logging.CC_ERROR(CLASSNAME, "Signature exception.");
return false;
}
}
}