Primer paso de la investigacion. Se aportan el .apk, las carpetas con el apk extraido y el apk descompilado. El archivo API_DOCUMENTATION.md es un archivo donde se anotaran los descubrimientos del funcionamiento de la API, y los .py son scripts para probar la funcionalidad de la API con los métodos que vayamos encontrando. Finalmente, los archivos .js son scripts de Frida para extraer informacion de la APP durante la ejecucion.
This commit is contained in:
@@ -0,0 +1,343 @@
|
||||
package com.google.firebase.remoteconfig.internal;
|
||||
|
||||
import C.w;
|
||||
import I2.k;
|
||||
import android.text.format.DateUtils;
|
||||
import c2.i;
|
||||
import c2.j;
|
||||
import com.google.android.gms.common.util.Clock;
|
||||
import com.google.android.gms.tasks.Continuation;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.android.gms.tasks.Tasks;
|
||||
import com.google.firebase.analytics.connector.AnalyticsConnector;
|
||||
import com.google.firebase.inject.Provider;
|
||||
import com.google.firebase.installations.FirebaseInstallationsApi;
|
||||
import com.google.firebase.installations.InstallationTokenResult;
|
||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException;
|
||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfigException;
|
||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException;
|
||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfigServerException;
|
||||
import com.google.firebase.remoteconfig.internal.ConfigMetadataClient;
|
||||
import com.google.firebase.sessions.settings.RemoteSettings;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/* loaded from: classes3.dex */
|
||||
public class ConfigFetchHandler {
|
||||
static final String FIRST_OPEN_TIME_KEY = "_fot";
|
||||
static final int HTTP_TOO_MANY_REQUESTS = 429;
|
||||
private static final String X_FIREBASE_RC_FETCH_TYPE = "X-Firebase-RC-Fetch-Type";
|
||||
private final Provider<AnalyticsConnector> analyticsConnector;
|
||||
private final Clock clock;
|
||||
private final Map<String, String> customHttpHeaders;
|
||||
private final Executor executor;
|
||||
private final ConfigCacheClient fetchedConfigsCache;
|
||||
private final FirebaseInstallationsApi firebaseInstallations;
|
||||
private final ConfigFetchHttpClient frcBackendApiClient;
|
||||
private final ConfigMetadataClient frcMetadata;
|
||||
private final Random randomGenerator;
|
||||
public static final long DEFAULT_MINIMUM_FETCH_INTERVAL_IN_SECONDS = TimeUnit.HOURS.toSeconds(12);
|
||||
static final int[] BACKOFF_TIME_DURATIONS_IN_MINUTES = {2, 4, 8, 16, 32, 64, 128, 256};
|
||||
|
||||
/* loaded from: classes3.dex */
|
||||
public static class FetchResponse {
|
||||
private final Date fetchTime;
|
||||
private final ConfigContainer fetchedConfigs;
|
||||
private final String lastFetchETag;
|
||||
private final int status;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
/* loaded from: classes3.dex */
|
||||
public @interface Status {
|
||||
public static final int BACKEND_HAS_NO_UPDATES = 1;
|
||||
public static final int BACKEND_UPDATES_FETCHED = 0;
|
||||
public static final int LOCAL_STORAGE_USED = 2;
|
||||
}
|
||||
|
||||
private FetchResponse(Date date, int i, ConfigContainer configContainer, String str) {
|
||||
this.fetchTime = date;
|
||||
this.status = i;
|
||||
this.fetchedConfigs = configContainer;
|
||||
this.lastFetchETag = str;
|
||||
}
|
||||
|
||||
public static FetchResponse forBackendHasNoUpdates(Date date, ConfigContainer configContainer) {
|
||||
return new FetchResponse(date, 1, configContainer, null);
|
||||
}
|
||||
|
||||
public static FetchResponse forBackendUpdatesFetched(ConfigContainer configContainer, String str) {
|
||||
return new FetchResponse(configContainer.getFetchTime(), 0, configContainer, str);
|
||||
}
|
||||
|
||||
public static FetchResponse forLocalStorageUsed(Date date) {
|
||||
return new FetchResponse(date, 2, null, null);
|
||||
}
|
||||
|
||||
public Date getFetchTime() {
|
||||
return this.fetchTime;
|
||||
}
|
||||
|
||||
public ConfigContainer getFetchedConfigs() {
|
||||
return this.fetchedConfigs;
|
||||
}
|
||||
|
||||
public String getLastFetchETag() {
|
||||
return this.lastFetchETag;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
}
|
||||
|
||||
/* loaded from: classes3.dex */
|
||||
public enum FetchType {
|
||||
BASE("BASE"),
|
||||
REALTIME("REALTIME");
|
||||
|
||||
private final String value;
|
||||
|
||||
FetchType(String str) {
|
||||
this.value = str;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigFetchHandler(FirebaseInstallationsApi firebaseInstallationsApi, Provider<AnalyticsConnector> provider, Executor executor, Clock clock, Random random, ConfigCacheClient configCacheClient, ConfigFetchHttpClient configFetchHttpClient, ConfigMetadataClient configMetadataClient, Map<String, String> map) {
|
||||
this.firebaseInstallations = firebaseInstallationsApi;
|
||||
this.analyticsConnector = provider;
|
||||
this.executor = executor;
|
||||
this.clock = clock;
|
||||
this.randomGenerator = random;
|
||||
this.fetchedConfigsCache = configCacheClient;
|
||||
this.frcBackendApiClient = configFetchHttpClient;
|
||||
this.frcMetadata = configMetadataClient;
|
||||
this.customHttpHeaders = map;
|
||||
}
|
||||
|
||||
private boolean areCachedFetchConfigsValid(long j4, Date date) {
|
||||
Date lastSuccessfulFetchTime = this.frcMetadata.getLastSuccessfulFetchTime();
|
||||
if (lastSuccessfulFetchTime.equals(ConfigMetadataClient.LAST_FETCH_TIME_NO_FETCH_YET)) {
|
||||
return false;
|
||||
}
|
||||
return date.before(new Date(TimeUnit.SECONDS.toMillis(j4) + lastSuccessfulFetchTime.getTime()));
|
||||
}
|
||||
|
||||
private FirebaseRemoteConfigServerException createExceptionWithGenericMessage(FirebaseRemoteConfigServerException firebaseRemoteConfigServerException) throws FirebaseRemoteConfigClientException {
|
||||
String str;
|
||||
int httpStatusCode = firebaseRemoteConfigServerException.getHttpStatusCode();
|
||||
if (httpStatusCode == 401) {
|
||||
str = "The request did not have the required credentials. Please make sure your google-services.json is valid.";
|
||||
} else if (httpStatusCode == 403) {
|
||||
str = "The user is not authorized to access the project. Please make sure you are using the API key that corresponds to your Firebase project.";
|
||||
} else {
|
||||
if (httpStatusCode == HTTP_TOO_MANY_REQUESTS) {
|
||||
throw new FirebaseRemoteConfigClientException("The throttled response from the server was not handled correctly by the FRC SDK.");
|
||||
}
|
||||
if (httpStatusCode != 500) {
|
||||
switch (httpStatusCode) {
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
str = "The server is unavailable. Please try again later.";
|
||||
break;
|
||||
default:
|
||||
str = "The server returned an unexpected error.";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
str = "There was an internal server error.";
|
||||
}
|
||||
}
|
||||
return new FirebaseRemoteConfigServerException(firebaseRemoteConfigServerException.getHttpStatusCode(), "Fetch failed: ".concat(str), firebaseRemoteConfigServerException);
|
||||
}
|
||||
|
||||
private String createThrottledMessage(long j4) {
|
||||
return w.z("Fetch is throttled. Please wait before calling fetch again: ", DateUtils.formatElapsedTime(TimeUnit.MILLISECONDS.toSeconds(j4)));
|
||||
}
|
||||
|
||||
private FetchResponse fetchFromBackend(String str, String str2, Date date, Map<String, String> map) throws FirebaseRemoteConfigException {
|
||||
Date date2;
|
||||
try {
|
||||
date2 = date;
|
||||
} catch (FirebaseRemoteConfigServerException e4) {
|
||||
e = e4;
|
||||
date2 = date;
|
||||
}
|
||||
try {
|
||||
FetchResponse fetch = this.frcBackendApiClient.fetch(this.frcBackendApiClient.createHttpURLConnection(), str, str2, getUserProperties(), this.frcMetadata.getLastFetchETag(), map, getFirstOpenTime(), date2);
|
||||
if (fetch.getFetchedConfigs() != null) {
|
||||
this.frcMetadata.setLastTemplateVersion(fetch.getFetchedConfigs().getTemplateVersionNumber());
|
||||
}
|
||||
if (fetch.getLastFetchETag() != null) {
|
||||
this.frcMetadata.setLastFetchETag(fetch.getLastFetchETag());
|
||||
}
|
||||
this.frcMetadata.resetBackoff();
|
||||
return fetch;
|
||||
} catch (FirebaseRemoteConfigServerException e5) {
|
||||
e = e5;
|
||||
FirebaseRemoteConfigServerException firebaseRemoteConfigServerException = e;
|
||||
ConfigMetadataClient.BackoffMetadata updateAndReturnBackoffMetadata = updateAndReturnBackoffMetadata(firebaseRemoteConfigServerException.getHttpStatusCode(), date2);
|
||||
if (shouldThrottle(updateAndReturnBackoffMetadata, firebaseRemoteConfigServerException.getHttpStatusCode())) {
|
||||
throw new FirebaseRemoteConfigFetchThrottledException(updateAndReturnBackoffMetadata.getBackoffEndTime().getTime());
|
||||
}
|
||||
throw createExceptionWithGenericMessage(firebaseRemoteConfigServerException);
|
||||
}
|
||||
}
|
||||
|
||||
private Task<FetchResponse> fetchFromBackendAndCacheResponse(String str, String str2, Date date, Map<String, String> map) {
|
||||
try {
|
||||
FetchResponse fetchFromBackend = fetchFromBackend(str, str2, date, map);
|
||||
return fetchFromBackend.getStatus() != 0 ? Tasks.forResult(fetchFromBackend) : this.fetchedConfigsCache.put(fetchFromBackend.getFetchedConfigs()).onSuccessTask(this.executor, new k(fetchFromBackend, 20));
|
||||
} catch (FirebaseRemoteConfigException e4) {
|
||||
return Tasks.forException(e4);
|
||||
}
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
/* renamed from: fetchIfCacheExpiredAndNotThrottled, reason: merged with bridge method [inline-methods] */
|
||||
public Task<FetchResponse> lambda$fetch$0(Task<ConfigContainer> task, long j4, final Map<String, String> map) {
|
||||
final ConfigFetchHandler configFetchHandler;
|
||||
Task continueWithTask;
|
||||
final Date date = new Date(this.clock.currentTimeMillis());
|
||||
if (task.isSuccessful() && areCachedFetchConfigsValid(j4, date)) {
|
||||
return Tasks.forResult(FetchResponse.forLocalStorageUsed(date));
|
||||
}
|
||||
Date backoffEndTimeInMillis = getBackoffEndTimeInMillis(date);
|
||||
if (backoffEndTimeInMillis != null) {
|
||||
continueWithTask = Tasks.forException(new FirebaseRemoteConfigFetchThrottledException(createThrottledMessage(backoffEndTimeInMillis.getTime() - date.getTime()), backoffEndTimeInMillis.getTime()));
|
||||
configFetchHandler = this;
|
||||
} else {
|
||||
final Task<String> id = this.firebaseInstallations.getId();
|
||||
final Task<InstallationTokenResult> token = this.firebaseInstallations.getToken(false);
|
||||
configFetchHandler = this;
|
||||
continueWithTask = Tasks.whenAllComplete((Task<?>[]) new Task[]{id, token}).continueWithTask(this.executor, new Continuation() { // from class: com.google.firebase.remoteconfig.internal.c
|
||||
@Override // com.google.android.gms.tasks.Continuation
|
||||
public final Object then(Task task2) {
|
||||
Task lambda$fetchIfCacheExpiredAndNotThrottled$2;
|
||||
lambda$fetchIfCacheExpiredAndNotThrottled$2 = ConfigFetchHandler.this.lambda$fetchIfCacheExpiredAndNotThrottled$2(id, token, date, map, task2);
|
||||
return lambda$fetchIfCacheExpiredAndNotThrottled$2;
|
||||
}
|
||||
});
|
||||
}
|
||||
return continueWithTask.continueWithTask(configFetchHandler.executor, new i(2, configFetchHandler, date));
|
||||
}
|
||||
|
||||
private Date getBackoffEndTimeInMillis(Date date) {
|
||||
Date backoffEndTime = this.frcMetadata.getBackoffMetadata().getBackoffEndTime();
|
||||
if (date.before(backoffEndTime)) {
|
||||
return backoffEndTime;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Long getFirstOpenTime() {
|
||||
AnalyticsConnector analyticsConnector = this.analyticsConnector.get();
|
||||
if (analyticsConnector == null) {
|
||||
return null;
|
||||
}
|
||||
return (Long) analyticsConnector.getUserProperties(true).get(FIRST_OPEN_TIME_KEY);
|
||||
}
|
||||
|
||||
private long getRandomizedBackoffDurationInMillis(int i) {
|
||||
TimeUnit timeUnit = TimeUnit.MINUTES;
|
||||
int[] iArr = BACKOFF_TIME_DURATIONS_IN_MINUTES;
|
||||
return (timeUnit.toMillis(iArr[Math.min(i, iArr.length) - 1]) / 2) + this.randomGenerator.nextInt((int) r0);
|
||||
}
|
||||
|
||||
private Map<String, String> getUserProperties() {
|
||||
HashMap hashMap = new HashMap();
|
||||
AnalyticsConnector analyticsConnector = this.analyticsConnector.get();
|
||||
if (analyticsConnector != null) {
|
||||
for (Map.Entry<String, Object> entry : analyticsConnector.getUserProperties(false).entrySet()) {
|
||||
hashMap.put(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
return hashMap;
|
||||
}
|
||||
|
||||
private boolean isThrottleableServerError(int i) {
|
||||
return i == HTTP_TOO_MANY_REQUESTS || i == 502 || i == 503 || i == 504;
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
public /* synthetic */ Task lambda$fetchIfCacheExpiredAndNotThrottled$2(Task task, Task task2, Date date, Map map, Task task3) throws Exception {
|
||||
return !task.isSuccessful() ? Tasks.forException(new FirebaseRemoteConfigClientException("Firebase Installations failed to get installation ID for fetch.", task.getException())) : !task2.isSuccessful() ? Tasks.forException(new FirebaseRemoteConfigClientException("Firebase Installations failed to get installation auth token for fetch.", task2.getException())) : fetchFromBackendAndCacheResponse((String) task.getResult(), ((InstallationTokenResult) task2.getResult()).getToken(), date, map);
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
public /* synthetic */ Task lambda$fetchIfCacheExpiredAndNotThrottled$3(Date date, Task task) throws Exception {
|
||||
updateLastFetchStatusAndTime(task, date);
|
||||
return task;
|
||||
}
|
||||
|
||||
/* JADX INFO: Access modifiers changed from: private */
|
||||
public /* synthetic */ Task lambda$fetchNowWithTypeAndAttemptNumber$1(Map map, Task task) throws Exception {
|
||||
return lambda$fetch$0(task, 0L, map);
|
||||
}
|
||||
|
||||
private boolean shouldThrottle(ConfigMetadataClient.BackoffMetadata backoffMetadata, int i) {
|
||||
return backoffMetadata.getNumFailedFetches() > 1 || i == HTTP_TOO_MANY_REQUESTS;
|
||||
}
|
||||
|
||||
private ConfigMetadataClient.BackoffMetadata updateAndReturnBackoffMetadata(int i, Date date) {
|
||||
if (isThrottleableServerError(i)) {
|
||||
updateBackoffMetadataWithLastFailedFetchTime(date);
|
||||
}
|
||||
return this.frcMetadata.getBackoffMetadata();
|
||||
}
|
||||
|
||||
private void updateBackoffMetadataWithLastFailedFetchTime(Date date) {
|
||||
int numFailedFetches = this.frcMetadata.getBackoffMetadata().getNumFailedFetches() + 1;
|
||||
this.frcMetadata.setBackoffMetadata(numFailedFetches, new Date(date.getTime() + getRandomizedBackoffDurationInMillis(numFailedFetches)));
|
||||
}
|
||||
|
||||
private void updateLastFetchStatusAndTime(Task<FetchResponse> task, Date date) {
|
||||
if (task.isSuccessful()) {
|
||||
this.frcMetadata.updateLastFetchAsSuccessfulAt(date);
|
||||
return;
|
||||
}
|
||||
Exception exception = task.getException();
|
||||
if (exception == null) {
|
||||
return;
|
||||
}
|
||||
if (exception instanceof FirebaseRemoteConfigFetchThrottledException) {
|
||||
this.frcMetadata.updateLastFetchAsThrottled();
|
||||
} else {
|
||||
this.frcMetadata.updateLastFetchAsFailed();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<FetchResponse> fetch() {
|
||||
return fetch(this.frcMetadata.getMinimumFetchIntervalInSeconds());
|
||||
}
|
||||
|
||||
public Task<FetchResponse> fetchNowWithTypeAndAttemptNumber(FetchType fetchType, int i) {
|
||||
HashMap hashMap = new HashMap(this.customHttpHeaders);
|
||||
hashMap.put(X_FIREBASE_RC_FETCH_TYPE, fetchType.getValue() + RemoteSettings.FORWARD_SLASH_STRING + i);
|
||||
return this.fetchedConfigsCache.get().continueWithTask(this.executor, new i(3, this, hashMap));
|
||||
}
|
||||
|
||||
public Provider<AnalyticsConnector> getAnalyticsConnector() {
|
||||
return this.analyticsConnector;
|
||||
}
|
||||
|
||||
public long getTemplateVersionNumber() {
|
||||
return this.frcMetadata.getLastTemplateVersion();
|
||||
}
|
||||
|
||||
public Task<FetchResponse> fetch(long j4) {
|
||||
HashMap hashMap = new HashMap(this.customHttpHeaders);
|
||||
hashMap.put(X_FIREBASE_RC_FETCH_TYPE, FetchType.BASE.getValue() + "/1");
|
||||
return this.fetchedConfigsCache.get().continueWithTask(this.executor, new j(this, j4, hashMap));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user