encrypt realms

still a lil crashy but works

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/287/head
androidacy-user 1 year ago
parent 5029486d4f
commit dac0c5ddde

@ -697,7 +697,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
Timber.i("Checking if we need to run setup");
// Check if this is the first launch
SharedPreferences prefs = MainApplication.getSharedPreferences("mmm");
boolean firstLaunch = prefs.getBoolean("first_time_setup_done", true);
boolean firstLaunch = prefs.getString("last_shown_setup", null) == null;
if (BuildConfig.DEBUG)
Timber.i("First launch: %s", firstLaunch);
if (firstLaunch) {

@ -12,6 +12,8 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.SystemClock;
import android.security.keystore.KeyProperties;
import android.util.Base64;
import android.util.Log;
import androidx.annotation.NonNull;
@ -37,7 +39,16 @@ import com.topjohnwu.superuser.Shell;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@ -47,6 +58,13 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Random;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import io.noties.markwon.Markwon;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.ImagesPlugin;
@ -513,4 +531,57 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
}
}
}
// Access the encrypted key in the keystore, decrypt it with the secret,
// and use it to open and read from the realm again
public byte[] getExistingKey() {
// open a connection to the android keystore
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
} catch (KeyStoreException | NoSuchAlgorithmException
| CertificateException | IOException e) {
throw new RuntimeException(e);
}
// access the encrypted key that's stored in shared preferences
byte[] initializationVectorAndEncryptedKey = Base64.decode(getSharedPreferences("realm_key")
.getString("iv_and_encrypted_key", null), Base64.DEFAULT);
ByteBuffer buffer = ByteBuffer.wrap(initializationVectorAndEncryptedKey);
buffer.order(ByteOrder.BIG_ENDIAN);
// extract the length of the initialization vector from the buffer
int initializationVectorLength = buffer.getInt();
// extract the initialization vector based on that length
byte[] initializationVector = new byte[initializationVectorLength];
buffer.get(initializationVector);
// extract the encrypted key
byte[] encryptedKey = new byte[initializationVectorAndEncryptedKey.length
- Integer.BYTES
- initializationVectorLength];
buffer.get(encryptedKey);
// create a cipher that uses AES encryption to decrypt our key
Cipher cipher;
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES
+ "/" + KeyProperties.BLOCK_MODE_CBC
+ "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException(e);
}
// decrypt the encrypted key with the secret key stored in the keystore
byte[] decryptedKey;
try {
final SecretKey secretKey =
(SecretKey) keyStore.getKey("realm_key", null);
final IvParameterSpec initializationVectorSpec =
new IvParameterSpec(initializationVector);
cipher.init(Cipher.DECRYPT_MODE, secretKey, initializationVectorSpec);
decryptedKey = cipher.doFinal(encryptedKey);
} catch (InvalidKeyException | UnrecoverableKeyException | NoSuchAlgorithmException |
BadPaddingException | KeyStoreException | IllegalBlockSizeException |
InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
return decryptedKey; // pass to a realm configuration via encryptionKey()
}
}

@ -10,6 +10,9 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Base64;
import android.view.View;
import android.view.WindowManager;
@ -36,15 +39,35 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Objects;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import timber.log.Timber;
public class SetupActivity extends FoxActivity implements LanguageActivity {
MasterKey mainKeyAlias;
@SuppressLint({"ApplySharedPref", "RestrictedApi"})
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -61,7 +84,6 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
actionBar.show();
}
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, 0);
createRealmDatabase();
createFiles();
disableUpdateActivityForFdroidFlavor();
// Set theme
@ -165,42 +187,27 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
// Set first launch to false
// get instance of editor
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("first_time_setup_done", false);
editor.putString("last_shown_setup", "v1");
// Set the Automatic update check pref
editor.putBoolean("pref_background_update_check", ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_background_update_check))).isChecked());
// Set the crash reporting pref
editor.putBoolean("pref_crash_reporting", ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_crash_reporting))).isChecked());
// Set the repos in the ReposList realm db
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).build();
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).allowQueriesOnUiThread(true).allowWritesOnUiThread(true).build();
boolean androidacyRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_androidacy_repo))).isChecked();
boolean magiskAltRepo = ((MaterialSwitch) Objects.requireNonNull(view.findViewById(R.id.setup_magisk_alt_repo))).isChecked();
Realm.getInstanceAsync(realmConfig, new Realm.Callback() {
@Override
public void onSuccess(@NonNull Realm realm) {
realm.executeTransaction(realm1 -> {
ReposList androidacyRepoDB = realm1.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst();
if (androidacyRepoDB != null) {
androidacyRepoDB.setEnabled(androidacyRepo);
}
ReposList magiskAltRepoDB = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst();
if (magiskAltRepoDB != null) {
magiskAltRepoDB.setEnabled(magiskAltRepo);
}
// commit the changes
realm1.commitTransaction();
realm1.close();
});
realm.commitTransaction();
realm.close();
}
});
Realm realm = Realm.getInstance(realmConfig);
Objects.requireNonNull(realm.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst()).setEnabled(androidacyRepo);
Objects.requireNonNull(realm.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst()).setEnabled(magiskAltRepo);
// commit the changes
realm.commitTransaction();
realm.close();
// Commit the changes
editor.commit();
// Sleep for 1 second to allow the user to see the changes
try {
Thread.sleep(500);
} catch (
InterruptedException e) {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Log the changes if debug
@ -219,7 +226,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
cancelButton.setText(R.string.cancel);
cancelButton.setOnClickListener(v -> {
// Set first launch to false and restart the activity
prefs.edit().putBoolean("first_time_setup_done", false).commit();
prefs.edit().putString("last_shown_setup", "v1").commit();
MainActivity.doSetupRestarting = true;
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
@ -258,9 +265,13 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
// creates the realm database
private void createRealmDatabase() {
Timber.d("Creating Realm databases");
// create encryption key
Timber.d("Creating encryption key");
// generate the encryption key and store it in the prefs
byte[] encryptionKey = getNewKey();
// create the realm database for ReposList
// next, create the realm database for ReposList
RealmConfiguration config2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration config2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).encryptionKey(encryptionKey).build();
// get the instance
Realm.getInstanceAsync(config2, new Realm.Callback() {
@Override
@ -308,14 +319,12 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
// initial set of cookies, only really used to create the keypair and encrypted file
String initialCookie = "is_foxmmm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/; domain=production-api.androidacy.com; SameSite=None; Secure;|foxmmm_version=" + BuildConfig.VERSION_CODE + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/; domain=production-api.androidacy.com; SameSite=None; Secure;";
Context context = getApplicationContext();
MasterKey mainKeyAlias;
mainKeyAlias = new MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build();
EncryptedFile encryptedFile = new EncryptedFile.Builder(context, new File(MainApplication.getINSTANCE().getFilesDir(), cookieFileName), mainKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).build();
InputStream inputStream;
try {
inputStream = encryptedFile.openFileInput();
} catch (
FileNotFoundException e) {
} catch (FileNotFoundException e) {
Timber.d("Cookie file not found, creating new file");
OutputStream outputStream = encryptedFile.openFileOutput();
outputStream.write(initialCookie.getBytes());
@ -337,8 +346,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
outputStream.close();
outputStream.flush();
}
} catch (GeneralSecurityException |
IOException e) {
} catch (GeneralSecurityException | IOException e) {
Timber.e(e);
}
// we literally only use these to create the http cache folders
@ -354,6 +362,7 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
Timber.d("Created http cache dir");
}
}
createRealmDatabase();
}
@SuppressWarnings("ConstantConditions")
@ -366,4 +375,69 @@ public class SetupActivity extends FoxActivity implements LanguageActivity {
pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
}
@SuppressLint("NewApi")
public byte[] getNewKey() {
if (MainApplication.getSharedPreferences("mmm").getBoolean("keygen", false)) {
Timber.d("Key already generated, returning");
return MainApplication.getINSTANCE().getExistingKey();
}
// open a connection to the android keystore
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
} catch (java.security.KeyStoreException | NoSuchAlgorithmException | CertificateException |
IOException e) {
throw new RuntimeException(e);
}
// create a securely generated random asymmetric RSA key
byte[] realmKey = new byte[Realm.ENCRYPTION_KEY_LENGTH];
new SecureRandom().nextBytes(realmKey);
// create a cipher that uses AES encryption -- we'll use this to encrypt our key
Cipher cipher;
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException(e);
}
// generate secret key
KeyGenerator keyGenerator;
try {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder("realm_key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT).setBlockModes(KeyProperties.BLOCK_MODE_CBC).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7).setUserAuthenticationRequired(false).build();
try {
keyGenerator.init(keySpec);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
keyGenerator.generateKey();
// access the generated key in the android keystore, then
// use the cipher to create an encrypted version of the key
byte[] initializationVector;
byte[] encryptedKeyForRealm;
try {
SecretKey secretKey = (SecretKey) keyStore.getKey("realm_key", null);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
encryptedKeyForRealm = cipher.doFinal(realmKey);
initializationVector = cipher.getIV();
} catch (InvalidKeyException | UnrecoverableKeyException | NoSuchAlgorithmException |
KeyStoreException | BadPaddingException | IllegalBlockSizeException e) {
throw new RuntimeException(e);
}
// keep the encrypted key in shared preferences
// to persist it across application runs
byte[] initializationVectorAndEncryptedKey = new byte[Integer.BYTES + initializationVector.length + encryptedKeyForRealm.length];
ByteBuffer buffer = ByteBuffer.wrap(initializationVectorAndEncryptedKey);
buffer.order(ByteOrder.BIG_ENDIAN);
buffer.putInt(initializationVector.length);
buffer.put(initializationVector);
buffer.put(encryptedKeyForRealm);
MainApplication.getSharedPreferences("realm_key").edit().putString("iv_and_encrypted_key", Base64.encodeToString(initializationVectorAndEncryptedKey, Base64.NO_WRAP)).apply();
MainApplication.getSharedPreferences("mmm").edit().putBoolean("keygen", true).apply();
return realmKey; // pass to a realm configuration via encryptionKey()
}
}

@ -208,7 +208,7 @@ public class BackgroundUpdateChecker extends Worker {
public static void onMainActivityCreate(Context context) {
// Refuse to run if first_launch pref is not false
if (MainApplication.getSharedPreferences("mmm").getBoolean("first_time_setup_done", true))
if (!Objects.equals(MainApplication.getSharedPreferences("mmm").getString("last_shown_setup", null), "v1"))
return;
// create notification channel group
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -219,7 +219,7 @@ public class BackgroundUpdateChecker extends Worker {
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
notificationManagerCompat.createNotificationChannel(new NotificationChannelCompat.Builder(NOTIFICATION_CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_HIGH).setShowBadge(true).setName(context.getString(R.string.notification_update_pref)).setDescription(context.getString(R.string.auto_updates_notifs)).setGroup(NOTFIICATION_GROUP).build());
notificationManagerCompat.cancel(BackgroundUpdateChecker.NOTIFICATION_ID);
WorkManager.getInstance(context).enqueueUniquePeriodicWork("background_checker", ExistingPeriodicWorkPolicy.REPLACE, new PeriodicWorkRequest.Builder(BackgroundUpdateChecker.class, 6, TimeUnit.HOURS).setConstraints(new Constraints.Builder().setRequiresBatteryNotLow(true).build()).build());
WorkManager.getInstance(context).enqueueUniquePeriodicWork("background_checker", ExistingPeriodicWorkPolicy.UPDATE, new PeriodicWorkRequest.Builder(BackgroundUpdateChecker.class, 6, TimeUnit.HOURS).setConstraints(new Constraints.Builder().setRequiresBatteryNotLow(true).build()).build());
}
public static void onMainActivityResume(Context context) {

@ -54,6 +54,10 @@ public final class ModuleManager extends SyncManager {
}
protected void scanInternal(@NonNull UpdateListener updateListener) {
// if last_shown_setup is not "v1", them=n refuse to continue
if (!MainApplication.getSharedPreferences("mmm").getString("last_shown_setup", "").equals("v1")) {
return;
}
boolean firstScan = this.bootPrefs.getBoolean("mm_first_scan", true);
SharedPreferences.Editor editor = firstScan ? this.bootPrefs.edit() : null;
for (ModuleInfo v : this.moduleInfos.values()) {
@ -90,7 +94,7 @@ public final class ModuleManager extends SyncManager {
// if the dir name matches the module name, use it as the cache dir
File tempCacheRoot = new File(dir.toString());
Timber.d("Looking for cache in %s", tempCacheRoot);
realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(tempCacheRoot).build();
realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(tempCacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration);
Timber.d("Looking for cache for %s out of %d", module, realm.where(ModuleListCache.class).count());
moduleListCache = realm.where(ModuleListCache.class).equalTo("codename", module).findFirst();

@ -36,11 +36,11 @@ import io.realm.RealmResults;
import timber.log.Timber;
public class RepoData extends XRepo {
public final String url;
public final String id;
public final File cacheRoot;
public final SharedPreferences cachedPreferences;
public final HashMap<String, RepoModule> moduleHashMap;
public String url;
public String id;
public File cacheRoot;
public SharedPreferences cachedPreferences;
public HashMap<String, RepoModule> moduleHashMap;
public final JSONObject supportedProperties = new JSONObject();
private final Object populateLock = new Object();
public JSONObject metaDataCache;
@ -72,6 +72,10 @@ public class RepoData extends XRepo {
private boolean forceHide, enabled; // Cache for speed
public RepoData(String url, File cacheRoot, SharedPreferences cachedPreferences) {
// if last_shown_setup is not "v1", them=n refuse to continue
if (!cachedPreferences.getString("last_shown_setup", "").equals("v1")) {
return;
}
// setup supportedProperties
try {
supportedProperties.put("id", "");
@ -106,7 +110,7 @@ public class RepoData extends XRepo {
this.defaultName = url; // Set url as default name
this.forceHide = AppUpdateManager.shouldForceHide(this.id);
// this.enable is set from the database
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm = Realm.getInstance(realmConfiguration);
ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst();
if (BuildConfig.DEBUG) {
@ -292,7 +296,7 @@ public class RepoData extends XRepo {
public void setEnabled(boolean enabled) {
this.enabled = enabled && !this.forceHide;
// reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
realm2.executeTransaction(realm -> {
ReposList reposList = realm.where(ReposList.class).equalTo("id", this.id).findFirst();
@ -310,7 +314,7 @@ public class RepoData extends XRepo {
}
this.forceHide = AppUpdateManager.shouldForceHide(this.id);
// reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
boolean dbEnabled;
try {
@ -369,12 +373,12 @@ public class RepoData extends XRepo {
// should update (lastUpdate > 15 minutes)
public boolean shouldUpdate() {
Timber.d("Repo " + this.id + " should update check called");
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
ReposList repo = realm2.where(ReposList.class).equalTo("id", this.id).findFirst();
// Make sure ModuleListCache for repoId is not null
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<ModuleListCache> moduleListCache = realm.where(ModuleListCache.class).equalTo("repoId", this.id).findAll();
if (repo != null) {

@ -147,6 +147,10 @@ public final class RepoManager extends SyncManager {
@SuppressWarnings("StatementWithEmptyBody")
private void populateDefaultCache(RepoData repoData) {
// if last_shown_setup is not "v1", them=n refuse to continue
if (!MainApplication.getSharedPreferences("mmm").getString("last_shown_setup", "").equals("v1")) {
return;
}
for (RepoModule repoModule : repoData.moduleHashMap.values()) {
if (!repoModule.moduleInfo.hasFlag(ModuleInfo.FLAG_METADATA_INVALID)) {
RepoModule registeredRepoModule = this.modules.get(repoModule.id);

@ -49,11 +49,11 @@ public class RepoUpdater {
if (!this.repoData.shouldUpdate()) {
Timber.d("Fetching index from cache for %s", this.repoData.id);
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<ModuleListCache> results = realm.where(ModuleListCache.class).equalTo("repoId", this.repoData.id).findAll();
// reposlist realm
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
this.toUpdate = Collections.emptyList();
this.toApply = new HashSet<>();
@ -122,7 +122,7 @@ public class RepoUpdater {
// use realm to insert to
// props avail:
File cacheRoot = MainApplication.getINSTANCE().getDataDirWithPath("realms/repos/" + this.repoData.id);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ModuleListCache.realm").schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).deleteRealmIfMigrationNeeded().allowWritesOnUiThread(true).allowQueriesOnUiThread(true).directory(cacheRoot).build();
// array with module info default values
// supported properties for a module
//id=<string>
@ -333,7 +333,7 @@ public class RepoUpdater {
Timber.w("Failed to get module info from %s with error %s", this.repoData.id, e.getMessage());
}
this.indexRaw = null;
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration2 = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm2 = Realm.getInstance(realmConfiguration2);
if (realm2.isInTransaction()) {
realm2.cancelTransaction();

@ -850,7 +850,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
});
}
// Get magisk_alt_repo enabled state from realm db
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfig = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm1 = Realm.getInstance(realmConfig);
ReposList reposList = realm1.where(ReposList.class).equalTo("id", "magisk_alt_repo").findFirst();
if (reposList != null) {
@ -885,7 +885,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
SwitchPreferenceCompat switchPreferenceCompat = (SwitchPreferenceCompat) androidacyRepoEnabled;
switchPreferenceCompat.setChecked(false);
// Disable in realm db
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm = Realm.getInstance(realmConfiguration);
realm.executeTransaction(realm2 -> {
ReposList repoRealmResults = realm2.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst();
@ -898,7 +898,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
});
}
// get if androidacy repo is enabled from realm db
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm = Realm.getInstance(realmConfiguration);
ReposList repoRealmResults = realm.where(ReposList.class).equalTo("id", "androidacy_repo").findFirst();
if (repoRealmResults == null) {
@ -1058,7 +1058,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
@SuppressLint("RestrictedApi")
public void updateCustomRepoList(boolean initial) {
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm = Realm.getInstance(realmConfiguration);
// get all repos that are not built-in
int CUSTOM_REPO_ENTRIES = 0;
@ -1184,7 +1184,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
return;
if (!preferenceName.contains("androidacy") && !preferenceName.contains("magisk_alt_repo")) {
if (repoData != null) {
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).build();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().name("ReposList.realm").allowQueriesOnUiThread(true).allowWritesOnUiThread(true).directory(MainApplication.getINSTANCE().getDataDirWithPath("realms")).schemaVersion(1).encryptionKey(MainApplication.getINSTANCE().getExistingKey()).build();
Realm realm = Realm.getInstance(realmConfiguration);
RealmResults<ReposList> repoDataRealmResults = realm.where(ReposList.class).equalTo("id", repoData.id).findAll();
Timber.d("Setting preference " + preferenceName + " because it is not the Androidacy repo or the Magisk Alt Repo");

@ -29,7 +29,7 @@ public class SentryMain {
public static void initialize(final MainApplication mainApplication) {
// If first_launch pref is not false, refuse to initialize Sentry
SharedPreferences sharedPreferences = MainApplication.getSharedPreferences("mmm");
if (sharedPreferences.getBoolean("first_time_setup_done", true)) {
if (!Objects.equals(sharedPreferences.getString("last_shown_setup", null), "v1")) {
return;
}
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {

Loading…
Cancel
Save