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,442 @@
|
||||
package com.google.firebase.storage;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.common.internal.Preconditions;
|
||||
import com.google.android.gms.common.util.Clock;
|
||||
import com.google.android.gms.common.util.DefaultClock;
|
||||
import com.google.firebase.appcheck.interop.InteropAppCheckTokenProvider;
|
||||
import com.google.firebase.auth.internal.InternalAuthProvider;
|
||||
import com.google.firebase.storage.StorageMetadata;
|
||||
import com.google.firebase.storage.internal.AdaptiveStreamBuffer;
|
||||
import com.google.firebase.storage.internal.ExponentialBackoffSender;
|
||||
import com.google.firebase.storage.internal.Sleeper;
|
||||
import com.google.firebase.storage.internal.SleeperImpl;
|
||||
import com.google.firebase.storage.internal.Util;
|
||||
import com.google.firebase.storage.network.NetworkRequest;
|
||||
import com.google.firebase.storage.network.ResumableUploadByteRequest;
|
||||
import com.google.firebase.storage.network.ResumableUploadCancelRequest;
|
||||
import com.google.firebase.storage.network.ResumableUploadQueryRequest;
|
||||
import com.google.firebase.storage.network.ResumableUploadStartRequest;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.json.JSONException;
|
||||
|
||||
/* loaded from: classes3.dex */
|
||||
public class UploadTask extends StorageTask<TaskSnapshot> {
|
||||
private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
|
||||
private static final int MAXIMUM_CHUNK_SIZE = 33554432;
|
||||
static final int PREFERRED_CHUNK_SIZE = 262144;
|
||||
private static final String RESUMABLE_FINAL_STATUS = "final";
|
||||
private static final String TAG = "UploadTask";
|
||||
private static final String X_GOOG_UPLOAD_URL = "X-Goog-Upload-URL";
|
||||
private final InteropAppCheckTokenProvider mAppCheckProvider;
|
||||
private final InternalAuthProvider mAuthProvider;
|
||||
private final AtomicLong mBytesUploaded;
|
||||
private int mCurrentChunkSize;
|
||||
private volatile Exception mException;
|
||||
private boolean mIsStreamOwned;
|
||||
private volatile StorageMetadata mMetadata;
|
||||
private volatile int mResultCode;
|
||||
private ExponentialBackoffSender mSender;
|
||||
private volatile Exception mServerException;
|
||||
private volatile String mServerStatus;
|
||||
private final StorageReference mStorageRef;
|
||||
private final AdaptiveStreamBuffer mStreamBuffer;
|
||||
private final long mTotalByteCount;
|
||||
private volatile Uri mUploadUri;
|
||||
private final Uri mUri;
|
||||
private volatile long maxSleepTime;
|
||||
private final int minimumSleepInterval;
|
||||
private int sleepTime;
|
||||
private static final Random random = new Random();
|
||||
static Sleeper sleeper = new SleeperImpl();
|
||||
static Clock clock = DefaultClock.getInstance();
|
||||
|
||||
/* loaded from: classes3.dex */
|
||||
public class TaskSnapshot extends StorageTask<TaskSnapshot>.SnapshotBase {
|
||||
private final long mBytesUploaded;
|
||||
private final StorageMetadata mMetadata;
|
||||
private final Uri mUploadUri;
|
||||
|
||||
public TaskSnapshot(Exception exc, long j4, Uri uri, StorageMetadata storageMetadata) {
|
||||
super(exc);
|
||||
this.mBytesUploaded = j4;
|
||||
this.mUploadUri = uri;
|
||||
this.mMetadata = storageMetadata;
|
||||
}
|
||||
|
||||
public long getBytesTransferred() {
|
||||
return this.mBytesUploaded;
|
||||
}
|
||||
|
||||
public StorageMetadata getMetadata() {
|
||||
return this.mMetadata;
|
||||
}
|
||||
|
||||
public long getTotalByteCount() {
|
||||
return UploadTask.this.getTotalByteCount();
|
||||
}
|
||||
|
||||
public Uri getUploadSessionUri() {
|
||||
return this.mUploadUri;
|
||||
}
|
||||
}
|
||||
|
||||
public UploadTask(StorageReference storageReference, StorageMetadata storageMetadata, byte[] bArr) {
|
||||
this.mBytesUploaded = new AtomicLong(0L);
|
||||
this.mCurrentChunkSize = PREFERRED_CHUNK_SIZE;
|
||||
this.mUploadUri = null;
|
||||
this.mException = null;
|
||||
this.mServerException = null;
|
||||
this.mResultCode = 0;
|
||||
this.sleepTime = 0;
|
||||
this.minimumSleepInterval = 1000;
|
||||
Preconditions.checkNotNull(storageReference);
|
||||
Preconditions.checkNotNull(bArr);
|
||||
FirebaseStorage storage = storageReference.getStorage();
|
||||
this.mTotalByteCount = bArr.length;
|
||||
this.mStorageRef = storageReference;
|
||||
this.mMetadata = storageMetadata;
|
||||
InternalAuthProvider authProvider = storage.getAuthProvider();
|
||||
this.mAuthProvider = authProvider;
|
||||
InteropAppCheckTokenProvider appCheckProvider = storage.getAppCheckProvider();
|
||||
this.mAppCheckProvider = appCheckProvider;
|
||||
this.mUri = null;
|
||||
this.mStreamBuffer = new AdaptiveStreamBuffer(new ByteArrayInputStream(bArr), PREFERRED_CHUNK_SIZE);
|
||||
this.mIsStreamOwned = true;
|
||||
this.maxSleepTime = storage.getMaxChunkUploadRetry();
|
||||
this.mSender = new ExponentialBackoffSender(storage.getApp().getApplicationContext(), authProvider, appCheckProvider, storage.getMaxDownloadRetryTimeMillis());
|
||||
}
|
||||
|
||||
private void beginResumableUpload() {
|
||||
String contentType = this.mMetadata != null ? this.mMetadata.getContentType() : null;
|
||||
if (this.mUri != null && TextUtils.isEmpty(contentType)) {
|
||||
contentType = this.mStorageRef.getStorage().getApp().getApplicationContext().getContentResolver().getType(this.mUri);
|
||||
}
|
||||
if (TextUtils.isEmpty(contentType)) {
|
||||
contentType = APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
ResumableUploadStartRequest resumableUploadStartRequest = new ResumableUploadStartRequest(this.mStorageRef.getStorageReferenceUri(), this.mStorageRef.getApp(), this.mMetadata != null ? this.mMetadata.createJSONObject() : null, contentType);
|
||||
if (sendWithRetry(resumableUploadStartRequest)) {
|
||||
String resultString = resumableUploadStartRequest.getResultString(X_GOOG_UPLOAD_URL);
|
||||
if (TextUtils.isEmpty(resultString)) {
|
||||
return;
|
||||
}
|
||||
this.mUploadUri = Uri.parse(resultString);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean delaySend(NetworkRequest networkRequest) {
|
||||
try {
|
||||
Log.d(TAG, "Waiting " + this.sleepTime + " milliseconds");
|
||||
sleeper.sleep(this.sleepTime + random.nextInt(250));
|
||||
boolean send = send(networkRequest);
|
||||
if (send) {
|
||||
this.sleepTime = 0;
|
||||
}
|
||||
return send;
|
||||
} catch (InterruptedException e4) {
|
||||
Log.w(TAG, "thread interrupted during exponential backoff.");
|
||||
Thread.currentThread().interrupt();
|
||||
this.mServerException = e4;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidHttpResponseCode(int i) {
|
||||
if (i != 308) {
|
||||
return i >= 200 && i < 300;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processResultValid(NetworkRequest networkRequest) {
|
||||
int resultCode = networkRequest.getResultCode();
|
||||
if (this.mSender.isRetryableError(resultCode)) {
|
||||
resultCode = -2;
|
||||
}
|
||||
this.mResultCode = resultCode;
|
||||
this.mServerException = networkRequest.getException();
|
||||
this.mServerStatus = networkRequest.getResultString("X-Goog-Upload-Status");
|
||||
return isValidHttpResponseCode(this.mResultCode) && this.mServerException == null;
|
||||
}
|
||||
|
||||
private boolean recoverStatus(boolean z3) {
|
||||
ResumableUploadQueryRequest resumableUploadQueryRequest = new ResumableUploadQueryRequest(this.mStorageRef.getStorageReferenceUri(), this.mStorageRef.getApp(), this.mUploadUri);
|
||||
if (RESUMABLE_FINAL_STATUS.equals(this.mServerStatus)) {
|
||||
return false;
|
||||
}
|
||||
if (z3) {
|
||||
if (!sendWithRetry(resumableUploadQueryRequest)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!send(resumableUploadQueryRequest)) {
|
||||
return false;
|
||||
}
|
||||
if (RESUMABLE_FINAL_STATUS.equals(resumableUploadQueryRequest.getResultString("X-Goog-Upload-Status"))) {
|
||||
this.mException = new IOException("The server has terminated the upload session");
|
||||
return false;
|
||||
}
|
||||
String resultString = resumableUploadQueryRequest.getResultString("X-Goog-Upload-Size-Received");
|
||||
long parseLong = !TextUtils.isEmpty(resultString) ? Long.parseLong(resultString) : 0L;
|
||||
long j4 = this.mBytesUploaded.get();
|
||||
if (j4 > parseLong) {
|
||||
this.mException = new IOException("Unexpected error. The server lost a chunk update.");
|
||||
return false;
|
||||
}
|
||||
if (j4 >= parseLong) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
if (this.mStreamBuffer.advance((int) r7) != parseLong - j4) {
|
||||
this.mException = new IOException("Unexpected end of stream encountered.");
|
||||
return false;
|
||||
}
|
||||
if (this.mBytesUploaded.compareAndSet(j4, parseLong)) {
|
||||
return true;
|
||||
}
|
||||
Log.e(TAG, "Somehow, the uploaded bytes changed during an uploaded. This should nothappen");
|
||||
this.mException = new IllegalStateException("uploaded bytes changed unexpectedly.");
|
||||
return false;
|
||||
} catch (IOException e4) {
|
||||
Log.e(TAG, "Unable to recover position in Stream during resumable upload", e4);
|
||||
this.mException = e4;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean send(NetworkRequest networkRequest) {
|
||||
networkRequest.performRequest(Util.getCurrentAuthToken(this.mAuthProvider), Util.getCurrentAppCheckToken(this.mAppCheckProvider), this.mStorageRef.getApp().getApplicationContext());
|
||||
return processResultValid(networkRequest);
|
||||
}
|
||||
|
||||
private boolean sendWithRetry(NetworkRequest networkRequest) {
|
||||
this.mSender.sendWithExponentialBackoff(networkRequest);
|
||||
return processResultValid(networkRequest);
|
||||
}
|
||||
|
||||
private boolean serverStateValid() {
|
||||
if (!RESUMABLE_FINAL_STATUS.equals(this.mServerStatus)) {
|
||||
return true;
|
||||
}
|
||||
if (this.mException == null) {
|
||||
this.mException = new IOException("The server has terminated the upload session", this.mServerException);
|
||||
}
|
||||
tryChangeState(64, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldContinue() {
|
||||
if (getInternalState() == 128) {
|
||||
return false;
|
||||
}
|
||||
if (Thread.interrupted()) {
|
||||
this.mException = new InterruptedException();
|
||||
tryChangeState(64, false);
|
||||
return false;
|
||||
}
|
||||
if (getInternalState() == 32) {
|
||||
tryChangeState(256, false);
|
||||
return false;
|
||||
}
|
||||
if (getInternalState() == 8) {
|
||||
tryChangeState(16, false);
|
||||
return false;
|
||||
}
|
||||
if (!serverStateValid()) {
|
||||
return false;
|
||||
}
|
||||
if (this.mUploadUri == null) {
|
||||
if (this.mException == null) {
|
||||
this.mException = new IllegalStateException("Unable to obtain an upload URL.");
|
||||
}
|
||||
tryChangeState(64, false);
|
||||
return false;
|
||||
}
|
||||
if (this.mException != null) {
|
||||
tryChangeState(64, false);
|
||||
return false;
|
||||
}
|
||||
boolean z3 = this.mServerException != null || this.mResultCode < 200 || this.mResultCode >= 300;
|
||||
long elapsedRealtime = clock.elapsedRealtime() + this.maxSleepTime;
|
||||
long elapsedRealtime2 = clock.elapsedRealtime() + this.sleepTime;
|
||||
if (z3) {
|
||||
if (elapsedRealtime2 > elapsedRealtime || !recoverStatus(true)) {
|
||||
if (serverStateValid()) {
|
||||
tryChangeState(64, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.sleepTime = Math.max(this.sleepTime * 2, 1000);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void uploadChunk() {
|
||||
try {
|
||||
this.mStreamBuffer.fill(this.mCurrentChunkSize);
|
||||
int min = Math.min(this.mCurrentChunkSize, this.mStreamBuffer.available());
|
||||
ResumableUploadByteRequest resumableUploadByteRequest = new ResumableUploadByteRequest(this.mStorageRef.getStorageReferenceUri(), this.mStorageRef.getApp(), this.mUploadUri, this.mStreamBuffer.get(), this.mBytesUploaded.get(), min, this.mStreamBuffer.isFinished());
|
||||
if (!delaySend(resumableUploadByteRequest)) {
|
||||
this.mCurrentChunkSize = PREFERRED_CHUNK_SIZE;
|
||||
Log.d(TAG, "Resetting chunk size to " + this.mCurrentChunkSize);
|
||||
return;
|
||||
}
|
||||
this.mBytesUploaded.getAndAdd(min);
|
||||
if (!this.mStreamBuffer.isFinished()) {
|
||||
this.mStreamBuffer.advance(min);
|
||||
int i = this.mCurrentChunkSize;
|
||||
if (i < MAXIMUM_CHUNK_SIZE) {
|
||||
this.mCurrentChunkSize = i * 2;
|
||||
Log.d(TAG, "Increasing chunk size to " + this.mCurrentChunkSize);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.mMetadata = new StorageMetadata.Builder(resumableUploadByteRequest.getResultBody(), this.mStorageRef).build();
|
||||
tryChangeState(4, false);
|
||||
tryChangeState(128, false);
|
||||
} catch (JSONException e4) {
|
||||
Log.e(TAG, "Unable to parse resulting metadata from upload:" + resumableUploadByteRequest.getRawResult(), e4);
|
||||
this.mException = e4;
|
||||
}
|
||||
} catch (IOException e5) {
|
||||
Log.e(TAG, "Unable to read bytes for uploading", e5);
|
||||
this.mException = e5;
|
||||
}
|
||||
}
|
||||
|
||||
@Override // com.google.firebase.storage.StorageTask
|
||||
public StorageReference getStorage() {
|
||||
return this.mStorageRef;
|
||||
}
|
||||
|
||||
public long getTotalByteCount() {
|
||||
return this.mTotalByteCount;
|
||||
}
|
||||
|
||||
@Override // com.google.firebase.storage.StorageTask
|
||||
public void onCanceled() {
|
||||
this.mSender.cancel();
|
||||
final ResumableUploadCancelRequest resumableUploadCancelRequest = this.mUploadUri != null ? new ResumableUploadCancelRequest(this.mStorageRef.getStorageReferenceUri(), this.mStorageRef.getApp(), this.mUploadUri) : null;
|
||||
if (resumableUploadCancelRequest != null) {
|
||||
StorageTaskScheduler.getInstance().scheduleCommand(new Runnable() { // from class: com.google.firebase.storage.UploadTask.1
|
||||
@Override // java.lang.Runnable
|
||||
public void run() {
|
||||
resumableUploadCancelRequest.performRequest(Util.getCurrentAuthToken(UploadTask.this.mAuthProvider), Util.getCurrentAppCheckToken(UploadTask.this.mAppCheckProvider), UploadTask.this.mStorageRef.getApp().getApplicationContext());
|
||||
}
|
||||
});
|
||||
}
|
||||
this.mException = StorageException.fromErrorStatus(Status.RESULT_CANCELED);
|
||||
super.onCanceled();
|
||||
}
|
||||
|
||||
@Override // com.google.firebase.storage.StorageTask
|
||||
public void resetState() {
|
||||
this.mException = null;
|
||||
this.mServerException = null;
|
||||
this.mResultCode = 0;
|
||||
this.mServerStatus = null;
|
||||
}
|
||||
|
||||
@Override // com.google.firebase.storage.StorageTask
|
||||
public void run() {
|
||||
this.mSender.reset();
|
||||
if (!tryChangeState(4, false)) {
|
||||
Log.d(TAG, "The upload cannot continue as it is not in a valid state.");
|
||||
return;
|
||||
}
|
||||
if (this.mStorageRef.getParent() == null) {
|
||||
this.mException = new IllegalArgumentException("Cannot upload to getRoot. You should upload to a storage location such as .getReference('image.png').putFile...");
|
||||
}
|
||||
if (this.mException != null) {
|
||||
return;
|
||||
}
|
||||
if (this.mUploadUri == null) {
|
||||
beginResumableUpload();
|
||||
} else {
|
||||
recoverStatus(false);
|
||||
}
|
||||
boolean shouldContinue = shouldContinue();
|
||||
while (shouldContinue) {
|
||||
uploadChunk();
|
||||
shouldContinue = shouldContinue();
|
||||
if (shouldContinue) {
|
||||
tryChangeState(4, false);
|
||||
}
|
||||
}
|
||||
if (!this.mIsStreamOwned || getInternalState() == 16) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.mStreamBuffer.close();
|
||||
} catch (IOException e4) {
|
||||
Log.e(TAG, "Unable to close stream.", e4);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // com.google.firebase.storage.StorageTask
|
||||
public void schedule() {
|
||||
StorageTaskScheduler.getInstance().scheduleUpload(getRunnable());
|
||||
}
|
||||
|
||||
@Override // com.google.firebase.storage.StorageTask
|
||||
public TaskSnapshot snapStateImpl() {
|
||||
return new TaskSnapshot(StorageException.fromExceptionAndHttpCode(this.mException != null ? this.mException : this.mServerException, this.mResultCode), this.mBytesUploaded.get(), this.mUploadUri, this.mMetadata);
|
||||
}
|
||||
|
||||
/* JADX WARN: Multi-variable type inference failed */
|
||||
/* JADX WARN: Removed duplicated region for block: B:12:0x00b1 */
|
||||
/* JADX WARN: Type inference failed for: r7v0, types: [com.google.firebase.auth.internal.InternalAuthProvider] */
|
||||
/* JADX WARN: Type inference failed for: r7v1 */
|
||||
/* JADX WARN: Type inference failed for: r7v10 */
|
||||
/* JADX WARN: Type inference failed for: r7v12 */
|
||||
/* JADX WARN: Type inference failed for: r7v13 */
|
||||
/* JADX WARN: Type inference failed for: r7v6 */
|
||||
/* JADX WARN: Type inference failed for: r7v8, types: [long] */
|
||||
/* JADX WARN: Type inference failed for: r7v9, types: [long] */
|
||||
/*
|
||||
Code decompiled incorrectly, please refer to instructions dump.
|
||||
To view partially-correct add '--show-bad-code' argument
|
||||
*/
|
||||
public UploadTask(com.google.firebase.storage.StorageReference r12, com.google.firebase.storage.StorageMetadata r13, android.net.Uri r14, android.net.Uri r15) {
|
||||
/*
|
||||
Method dump skipped, instructions count: 239
|
||||
To view this dump add '--comments-level debug' option
|
||||
*/
|
||||
throw new UnsupportedOperationException("Method not decompiled: com.google.firebase.storage.UploadTask.<init>(com.google.firebase.storage.StorageReference, com.google.firebase.storage.StorageMetadata, android.net.Uri, android.net.Uri):void");
|
||||
}
|
||||
|
||||
public UploadTask(StorageReference storageReference, StorageMetadata storageMetadata, InputStream inputStream) {
|
||||
this.mBytesUploaded = new AtomicLong(0L);
|
||||
this.mCurrentChunkSize = PREFERRED_CHUNK_SIZE;
|
||||
this.mUploadUri = null;
|
||||
this.mException = null;
|
||||
this.mServerException = null;
|
||||
this.mResultCode = 0;
|
||||
this.sleepTime = 0;
|
||||
this.minimumSleepInterval = 1000;
|
||||
Preconditions.checkNotNull(storageReference);
|
||||
Preconditions.checkNotNull(inputStream);
|
||||
FirebaseStorage storage = storageReference.getStorage();
|
||||
this.mTotalByteCount = -1L;
|
||||
this.mStorageRef = storageReference;
|
||||
this.mMetadata = storageMetadata;
|
||||
InternalAuthProvider authProvider = storage.getAuthProvider();
|
||||
this.mAuthProvider = authProvider;
|
||||
InteropAppCheckTokenProvider appCheckProvider = storage.getAppCheckProvider();
|
||||
this.mAppCheckProvider = appCheckProvider;
|
||||
this.mStreamBuffer = new AdaptiveStreamBuffer(inputStream, PREFERRED_CHUNK_SIZE);
|
||||
this.mIsStreamOwned = false;
|
||||
this.mUri = null;
|
||||
this.maxSleepTime = storage.getMaxChunkUploadRetry();
|
||||
this.mSender = new ExponentialBackoffSender(storageReference.getApp().getApplicationContext(), authProvider, appCheckProvider, storage.getMaxUploadRetryTimeMillis());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user