Skip to content

Commit

Permalink
Apollo: Release source code for 49.3
Browse files Browse the repository at this point in the history
  • Loading branch information
acrespo committed Apr 26, 2022
1 parent 0c8baab commit e65b56b
Show file tree
Hide file tree
Showing 77 changed files with 1,235 additions and 309 deletions.
10 changes: 10 additions & 0 deletions android/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ follow [https://changelog.md/](https://changelog.md/) guidelines.

## [Unreleased]

## [49.3] - 2022-04-26

### ADDED
- Better error reporting and extra metadata for MoneyDecoration (MuunAmountInput) crash

### FIXED
- Added missing error metadata to some crashlytics errors (e.g for background task of anon users)
- Invoice expiration time label getting cut off due to very long expiration time formatting
- Avoid crashing and add debug snapshot with audit trail for SecureStorageErrors

## [49.2] - 2022-03-22

### FIXED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.muun.apollo.data.net.ModelObjectsMapper;
import io.muun.apollo.data.os.execution.ExecutionTransformerFactory;
import io.muun.apollo.data.serialization.SerializationUtils;
import io.muun.apollo.domain.LoggingContextManager;
import io.muun.apollo.domain.action.NotificationActions;
import io.muun.apollo.domain.action.fcm.UpdateFcmTokenAction;
import io.muun.apollo.domain.errors.FcmMessageProcessingError;
Expand All @@ -20,6 +21,9 @@

public class GcmMessageListenerService extends FirebaseMessagingService {

@Inject
LoggingContextManager loggingContextManager;

@Inject
DaoManager daoManager; // not used directly by us, but needed in case we start the Application

Expand All @@ -46,6 +50,8 @@ public void onCreate() {
provider.getDataComponent().inject(this);

Timber.d("Starting GcmMessageListenerService");

loggingContextManager.setupCrashlytics();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.work.WorkerParameters
import io.muun.apollo.data.external.DataComponentProvider
import io.muun.apollo.data.external.NotificationService
import io.muun.apollo.data.os.execution.ExecutionTransformerFactory
import io.muun.apollo.domain.LoggingContextManager
import io.muun.apollo.domain.action.UserActions
import io.muun.apollo.domain.errors.MuunError
import io.muun.common.utils.Preconditions
Expand All @@ -28,6 +29,9 @@ class MuunWorkerFactory(provider: DataComponentProvider) : WorkerFactory() {
@Inject
lateinit var userActions: UserActions

@Inject
lateinit var loggingContextManager: LoggingContextManager

@Inject
lateinit var transformerFactory: ExecutionTransformerFactory

Expand All @@ -48,6 +52,8 @@ class MuunWorkerFactory(provider: DataComponentProvider) : WorkerFactory() {
// Should be enforce by WorkManager API but still (why don't they use Class param?!)
Preconditions.checkArgument(Worker::class.java.isAssignableFrom(workerClass))

loggingContextManager.setupCrashlytics()

when (workerClass) {
PeriodicTaskWorker::class.java -> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.muun.apollo.domain.action.UserActions;
import io.muun.apollo.domain.errors.NoStackTraceException;
import io.muun.apollo.domain.errors.PeriodicTaskError;
import io.muun.common.utils.Preconditions;

import android.content.Context;
import android.os.SystemClock;
Expand Down Expand Up @@ -51,7 +52,7 @@ public Result doWork() {
// minutes of execution if your task has not returned it will be considered to have timed
// out, and the wakelock will be released.

final String type = getInputData().getString(TASK_TYPE_KEY);
final String type = Preconditions.checkNotNull(getInputData().getString(TASK_TYPE_KEY));

Timber.d("Running periodic task of type %s", type);

Expand All @@ -60,30 +61,30 @@ public Result doWork() {
try {

taskDispatcher.dispatch(type)
.doOnError(throwable -> {

if (throwable.getStackTrace() == null) {
fillInStackTrace(throwable);
}

if (throwable.getStackTrace() == null) {

final String message = String.format(
"Exception of type %s with no stacktrace, while running a periodic "
+ "task of type %s. Message: %s.",
throwable.getClass().getCanonicalName(),
type,
throwable.getMessage()
);

throwable = new NoStackTraceException(message);
}

Timber.e(throwable);
})
.compose(transformerFactory.getAsyncExecutor())
.toBlocking()
.subscribe();
.doOnError(throwable -> {

if (throwable.getStackTrace() == null) {
fillInStackTrace(throwable);
}

if (throwable.getStackTrace() == null) {

final String message = String.format(
"Exception of type %s with no stacktrace, while running a "
+ "periodic task of type %s. Message: %s.",
throwable.getClass().getCanonicalName(),
type,
throwable.getMessage()
);

throwable = new NoStackTraceException(message);
}

Timber.e(throwable);
})
.compose(transformerFactory.getAsyncExecutor())
.toBlocking()
.subscribe();

} catch (RuntimeException error) {
Timber.e(new PeriodicTaskError(type, secondsSince(startMs), error));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
Expand Down Expand Up @@ -79,6 +81,8 @@ private void generateKeyStore(String keyAlias) {
}

/**
* Encrypt a value using an unique keystore-backed key.
*
* @param input Data to encrypt.
* @param alias Key alias under which a key will be generated in the keystore.
* @param iv Initialization vector which will prevent an attacker to easily figure out the
Expand All @@ -91,6 +95,9 @@ public byte[] encryptData(byte[] input, String alias, byte[] iv) {
final String keyAlias = getAlias(alias);

if (!hasKey(keyAlias)) {
// FIXME: This is a racy operation and might end up creating 2 keys overwriting
// each other. That might mean we store the encrypted value using key 1 but keystore
// has key 2 stored.
generateKeyStore(keyAlias);
}

Expand All @@ -105,6 +112,8 @@ public byte[] encryptData(byte[] input, String alias, byte[] iv) {
}

/**
* Decrypt a value using it's unique key backed by the keystore.
*
* @param input Data to decrypt.
* @param alias Key alias under which the data was encrypted in the first place.
* @param iv Initialization vector that was user to encrypt the data.
Expand Down Expand Up @@ -141,10 +150,10 @@ private void generateKeyStoreM(String keyAlias) {

keyGenerator.generateKey();

} catch (
NoSuchAlgorithmException
| NoSuchProviderException
| InvalidAlgorithmParameterException e) {
} catch (NoSuchAlgorithmException
| NoSuchProviderException
| InvalidAlgorithmParameterException e) {

Timber.e(e);
throw new MuunKeyStoreException(e);
}
Expand Down Expand Up @@ -205,10 +214,10 @@ private void generateKeyStoreJ(String keyAlias) {
generator.initialize(spec);
generator.generateKeyPair();

} catch (
NoSuchAlgorithmException
| NoSuchProviderException
| InvalidAlgorithmParameterException e) {
} catch (NoSuchAlgorithmException
| NoSuchProviderException
| InvalidAlgorithmParameterException e) {

Timber.e(e);
throw new MuunKeyStoreException(e);
}
Expand All @@ -217,45 +226,44 @@ private void generateKeyStoreJ(String keyAlias) {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private byte[] encryptDataJ(byte[] inputData, String keyAlias, KeyStore keyStore) {
try {
final PrivateKeyEntry privateKeyEntry
= (PrivateKeyEntry) keyStore.getEntry(keyAlias, null);

return CryptographyWrapper.rsaEncrypt(inputData, privateKeyEntry);

} catch (
KeyStoreException
| NoSuchAlgorithmException
| UnrecoverableEntryException
| InvalidKeyException
| NoSuchPaddingException
| IOException e) {
final PrivateKeyEntry entry = (PrivateKeyEntry) keyStore.getEntry(keyAlias, null);

return CryptographyWrapper.rsaEncrypt(inputData, entry);

} catch (KeyStoreException
| NoSuchAlgorithmException
| UnrecoverableEntryException
| InvalidKeyException
| NoSuchPaddingException
| IOException e) {

Timber.e(e);
throw new MuunKeyStoreException(e);
}
}

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private byte[] decryptDataJ(byte[] input, String keyAlias, KeyStore keyStore) {
PrivateKeyEntry privateKeyEntry = null;
try {
privateKeyEntry = (PrivateKeyEntry) keyStore.getEntry(keyAlias,
null);

return CryptographyWrapper.rsaDecrypt(input, privateKeyEntry);

} catch (
NoSuchAlgorithmException
| NoSuchPaddingException
| UnrecoverableEntryException
| KeyStoreException
| InvalidKeyException
| IOException e) {
final PrivateKeyEntry entry = (PrivateKeyEntry) keyStore.getEntry(keyAlias, null);

return CryptographyWrapper.rsaDecrypt(input, entry);

} catch (NoSuchAlgorithmException
| NoSuchPaddingException
| UnrecoverableEntryException
| KeyStoreException
| InvalidKeyException
| IOException e) {

Timber.e(e);
throw new MuunKeyStoreException(e);
}
}

/**
* Check whether an alias is present in the keystore.
*
* @param keyAlias Key alias that was used to encrypt data.
* @return True if that key was generated.
*/
Expand Down Expand Up @@ -312,6 +320,14 @@ public void wipe() {
}
}

Set<String> getAllLabels() throws MuunKeyStoreException {
try {
return new HashSet<>(Collections.list(loadKeystore().aliases()));
} catch (KeyStoreException e) {
throw new MuunKeyStoreException(e);
}
}

public static class MuunKeyStoreException extends CryptographyException {

public MuunKeyStoreException(Throwable cause) {
Expand Down
Loading

0 comments on commit e65b56b

Please sign in to comment.