Security fixes and optimizations

- All known hosts now have a hardcoded trusted root ca, because we're not just going to trust that the user has a-ok certs installed
- Remove some unused code
- Properly fix a couple NetworkOnMainThread errors

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/242/head
androidacy-user 1 year ago
parent 86c46de069
commit 66cb0b1813

@ -50,7 +50,6 @@ import com.fox2code.mmm.utils.BlurUtils;
import com.fox2code.mmm.utils.ExternalHelper;
import com.fox2code.mmm.utils.Http;
import com.fox2code.mmm.utils.IntentHelper;
import com.fox2code.mmm.utils.NoodleDebug;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.LinearProgressIndicator;
@ -71,7 +70,6 @@ import io.sentry.Sentry;
public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRefreshListener, SearchView.OnQueryTextListener, SearchView.OnCloseListener, OverScrollManager.OverScrollHelper {
private static final String TAG = "MainActivity";
private static final int PRECISION = 10000;
public static boolean noodleDebugState = BuildConfig.DEBUG;
public final ModuleViewListBuilder moduleViewListBuilder;
public LinearProgressIndicator progressIndicator;
private ModuleViewAdapter moduleViewAdapter;
@ -87,7 +85,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
private RecyclerView moduleList;
private CardView searchCard;
private SearchView searchView;
private NoodleDebug noodleDebug;
private boolean initMode;
public MainActivity() {
@ -104,7 +101,8 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
@Override
protected void onCreate(Bundle savedInstanceState) {
this.initMode = true;
noodleDebugState = MainApplication.isDeveloper();
// Ensure HTTP Cache directories are created
Http.ensureCacheDirs(this);
BackgroundUpdateChecker.onMainActivityCreate(this);
super.onCreate(savedInstanceState);
this.setActionBarExtraMenuButton(R.drawable.ic_baseline_settings_24, v -> {
@ -132,7 +130,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
this.moduleList = findViewById(R.id.module_list);
this.searchCard = findViewById(R.id.search_card);
this.searchView = findViewById(R.id.search_bar);
this.noodleDebug = new NoodleDebug(this, R.id.noodle_debug);
this.moduleViewAdapter = new ModuleViewAdapter();
this.moduleList.setAdapter(this.moduleViewAdapter);
this.moduleList.setLayoutManager(new LinearLayoutManager(this));
@ -290,6 +287,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
dialog.cancel();
}
preferences.edit().remove("lastEventId").apply();
preferences.edit().putString("lastExitReason", "").apply();
// Prevent strict mode violation
new Thread(() -> {
try {
@ -439,8 +437,6 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe
@Override
public void onFailure(int error) {
moduleViewListBuilder.addNotification(InstallerInitializer.getErrorNotification());
noodleDebug.setEnabled(noodleDebugState);
noodleDebug.bind();
this.commonNext();
}

@ -258,7 +258,7 @@ public final class AndroidacyActivity extends FoxActivity {
break;
}
}
return super.onConsoleMessage(consoleMessage);
return true;
}
@Override

@ -13,10 +13,12 @@ public class BackgroundBootListener extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (!BOOT_COMPLETED.equals(intent.getAction())) return;
synchronized (BackgroundUpdateChecker.lock) {
BackgroundUpdateChecker.onMainActivityCreate(context);
if (MainApplication.isBackgroundUpdateCheckEnabled()) {
BackgroundUpdateChecker.doCheck(context);
}
new Thread(() -> {
BackgroundUpdateChecker.onMainActivityCreate(context);
if (MainApplication.isBackgroundUpdateCheckEnabled()) {
BackgroundUpdateChecker.doCheck(context);
}
}).start();
}
}
}

@ -4,7 +4,6 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.StrictMode;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationChannelCompat;
@ -54,10 +53,7 @@ public class BackgroundUpdateChecker extends Worker {
}
static void doCheck(Context context) {
// This is actually not recommended but it's the only way to do it
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
Thread.currentThread().setPriority(2);
ModuleManager.getINSTANCE().scanAsync();
RepoManager.getINSTANCE().update(null);
ModuleManager.getINSTANCE().runAfterScan(() -> {

@ -8,8 +8,6 @@ import androidx.annotation.NonNull;
import com.fox2code.mmm.BuildConfig;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.installer.InstallerInitializer;
import com.fox2code.mmm.utils.Http;
import com.fox2code.mmm.utils.NoodleDebug;
import com.fox2code.mmm.utils.PropUtils;
import com.fox2code.mmm.utils.SyncManager;
import com.topjohnwu.superuser.Shell;
@ -24,33 +22,34 @@ import java.util.HashMap;
import java.util.Iterator;
public final class ModuleManager extends SyncManager {
private static final String TAG = "ModuleManager";
// New method is not really effective, this flag force app to use old method
public static final boolean FORCE_NEED_FALLBACK = true;
private static final String TAG = "ModuleManager";
private static final int FLAG_MM_INVALID = ModuleInfo.FLAG_METADATA_INVALID;
private static final int FLAG_MM_UNPROCESSED = ModuleInfo.FLAG_CUSTOM_INTERNAL;
private static final int FLAGS_KEEP_INIT = FLAG_MM_UNPROCESSED |
ModuleInfo.FLAGS_MODULE_ACTIVE | ModuleInfo.FLAG_MODULE_UPDATING_ONLY;
private static final int FLAGS_RESET_UPDATE = FLAG_MM_INVALID | FLAG_MM_UNPROCESSED;
private static final ModuleManager INSTANCE = new ModuleManager();
private final HashMap<String, LocalModuleInfo> moduleInfos;
private final SharedPreferences bootPrefs;
private int updatableModuleCount = 0;
private static final ModuleManager INSTANCE = new ModuleManager();
private ModuleManager() {
this.moduleInfos = new HashMap<>();
this.bootPrefs = MainApplication.getBootSharedPreferences();
}
public static ModuleManager getINSTANCE() {
return INSTANCE;
}
private ModuleManager() {
this.moduleInfos = new HashMap<>();
this.bootPrefs = MainApplication.getBootSharedPreferences();
public static boolean isModuleActive(String moduleId) {
ModuleInfo moduleInfo = ModuleManager.getINSTANCE().getModules().get(moduleId);
return moduleInfo != null && (moduleInfo.flags & ModuleInfo.FLAGS_MODULE_ACTIVE) != 0;
}
protected void scanInternal(@NonNull UpdateListener updateListener) {
NoodleDebug noodleDebug = NoodleDebug.getNoodleDebug();
noodleDebug.push("Initialize scan");
boolean firstScan = this.bootPrefs.getBoolean("mm_first_scan", true);
SharedPreferences.Editor editor = firstScan ? this.bootPrefs.edit() : null;
for (ModuleInfo v : this.moduleInfos.values()) {
@ -73,7 +72,6 @@ public final class ModuleManager extends SyncManager {
}
if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Scan");
if (modules != null) {
noodleDebug.push("");
for (String module : modules) {
if (!new SuFile("/data/adb/modules/" + module).isDirectory())
continue; // Ignore non directory files inside modules folder
@ -123,7 +121,6 @@ public final class ModuleManager extends SyncManager {
if (BuildConfig.DEBUG) Log.d("NoodleDebug", "Scan update");
String[] modules_update = new SuFile("/data/adb/modules_update").list();
if (modules_update != null) {
noodleDebug.push("");
for (String module : modules_update) {
if (!new SuFile("/data/adb/modules_update/" + module).isDirectory())
continue; // Ignore non directory files inside modules folder
@ -148,7 +145,6 @@ public final class ModuleManager extends SyncManager {
this.updatableModuleCount = 0;
Iterator<LocalModuleInfo> moduleInfoIterator =
this.moduleInfos.values().iterator();
noodleDebug.push("");
while (moduleInfoIterator.hasNext()) {
LocalModuleInfo moduleInfo = moduleInfoIterator.next();
if (BuildConfig.DEBUG) Log.d("NoodleDebug", moduleInfo.id);
@ -232,7 +228,7 @@ public final class ModuleManager extends SyncManager {
try { // Check for module that declare having file outside their own folder.
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
SuFileInputStream.open("/data/adb/modules/." + moduleInfo.id + "-files"),
StandardCharsets.UTF_8))) {
StandardCharsets.UTF_8))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
line = line.trim().replace(' ', '.');
@ -245,16 +241,12 @@ public final class ModuleManager extends SyncManager {
Shell.cmd("rm -rf \"" + line + "\"").exec();
}
}
} catch (IOException ignored) {}
} catch (IOException ignored) {
}
Shell.cmd("rm -rf /data/adb/modules/" + escapedId + "/").exec();
Shell.cmd("rm -f /data/adb/modules/." + escapedId + "-files").exec();
Shell.cmd("rm -rf /data/adb/modules_update/" + escapedId + "/").exec();
moduleInfo.flags = ModuleInfo.FLAG_METADATA_INVALID;
return true;
}
public static boolean isModuleActive(String moduleId) {
ModuleInfo moduleInfo = ModuleManager.getINSTANCE().getModules().get(moduleId);
return moduleInfo != null && (moduleInfo.flags & ModuleInfo.FLAGS_MODULE_ACTIVE) != 0;
}
}

@ -537,6 +537,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
// Use MaterialAlertDialogBuilder
new MaterialAlertDialogBuilder(this.requireContext())
.setTitle(R.string.warning)
.setCancelable(false)
.setMessage(R.string.androidacy_test_mode_warning)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
// User clicked OK button
@ -575,6 +576,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
// Show dialog to restart app with ok button
new MaterialAlertDialogBuilder(this.requireContext())
.setTitle(R.string.warning)
.setCancelable(false)
.setMessage(R.string.androidacy_test_mode_disable_warning)
.setNeutralButton(android.R.string.ok, (dialog, which) -> {
// User clicked OK button
@ -609,6 +611,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
androidacyRepoEnabled.setOnPreferenceClickListener(preference -> {
new MaterialAlertDialogBuilder(this.requireContext())
.setTitle(R.string.androidacy_repo_disabled)
.setCancelable(false)
.setMessage(R.string.androidacy_repo_disabled_message)
.setPositiveButton(R.string.download_full_app, (dialog, which) -> {
// User clicked OK button. Open GitHub releases page
@ -664,6 +667,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
// Show dialog to restart app with ok button
new MaterialAlertDialogBuilder(this.requireContext())
.setTitle(R.string.restart)
.setCancelable(false)
.setMessage(R.string.api_key_restart)
.setNeutralButton(android.R.string.ok, (dialog, which) -> {
// User clicked OK button
@ -721,6 +725,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity {
// Show dialog to restart app with ok button
new MaterialAlertDialogBuilder(this.requireContext())
.setTitle(R.string.restart)
.setCancelable(false)
.setMessage(R.string.api_key_restart)
.setNeutralButton(android.R.string.ok, (dialog, which) -> {
// User clicked OK button

@ -15,6 +15,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.fox2code.mmm.BuildConfig;
import com.fox2code.mmm.MainActivity;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.androidacy.AndroidacyUtil;
import com.fox2code.mmm.installer.InstallerInitializer;
@ -341,6 +342,29 @@ public class Http {
return hasWebView;
}
public static void ensureCacheDirs(MainActivity mainActivity) {
File cacheDir = mainActivity.getCacheDir();
File cacheDir2 = new File(cacheDir, "HTTP Cache");
if (!cacheDir2.exists()) {
if (!cacheDir2.mkdirs()) {
Log.e(TAG, "Failed to create cache dir");
}
}
// Ensure js and wasm cache dirs
File jsCacheDir = new File(cacheDir2, "js");
if (!jsCacheDir.exists()) {
if (!jsCacheDir.mkdirs()) {
Log.e(TAG, "Failed to create js cache dir");
}
}
File wasmCacheDir = new File(cacheDir2, "wasm");
if (!wasmCacheDir.exists()) {
if (!wasmCacheDir.mkdirs()) {
Log.e(TAG, "Failed to create wasm cache dir");
}
}
}
public interface ProgressListener {
void onUpdate(int downloaded, int total, boolean done);
}

@ -1,171 +0,0 @@
package com.fox2code.mmm.utils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.Objects;
public class NoodleDebug {
private static final String TAG = "NoodleDebug";
private static final WeakReference<Thread> NULL_THREAD_REF = new WeakReference<>(null);
private static final ThreadLocal<NoodleDebug> THREAD_NOODLE = new ThreadLocal<>();
@SuppressLint("StaticFieldLeak") // <- Null initialized
private static final NoodleDebug NULL = new NoodleDebug() {
@Override
public NoodleDebug bind() {
getNoodleDebug().unbind();
THREAD_NOODLE.remove();
return this;
}
@Override
public void setEnabled(boolean enabled) {}
@Override
protected void markDirty() {}
};
private final Activity activity;
private final TextView textView;
private final LinkedList<String> tokens;
private final StringBuilder debug;
private WeakReference<Thread> thread;
private boolean enabled, updating;
private NoodleDebug() {
this.activity = null;
this.textView = null;
this.tokens = new LinkedList<>();
this.debug = new StringBuilder(0);
this.thread = NULL_THREAD_REF;
}
public NoodleDebug(Activity activity,@IdRes int textViewId) {
this(activity, activity.findViewById(textViewId));
}
public NoodleDebug(Activity activity, TextView textView) {
this.activity = Objects.requireNonNull(activity);
this.textView = Objects.requireNonNull(textView);
this.tokens = new LinkedList<>();
this.debug = new StringBuilder(64);
this.thread = NULL_THREAD_REF;
}
public NoodleDebug bind() {
synchronized (this.tokens) {
Thread thread;
if ((thread = this.thread.get()) != null) {
Log.e(TAG, "Trying to bind to thread \"" + Thread.currentThread().getName() +
"\" while already bound to \"" + thread.getName() + "\"");
return NULL;
}
this.tokens.clear();
}
if (this.enabled) {
this.thread = new WeakReference<>(Thread.currentThread());
THREAD_NOODLE.set(this);
} else {
this.thread = NULL_THREAD_REF;
THREAD_NOODLE.remove();
}
return this;
}
public void unbind() {
this.thread = NULL_THREAD_REF;
boolean markDirty;
synchronized (this.tokens) {
markDirty = !this.tokens.isEmpty();
this.tokens.clear();
}
if (markDirty) this.markDirty();
}
public boolean isBound() {
return this.thread.get() != null;
}
public void push(String token) {
if (!this.enabled) return;
synchronized (this.tokens) {
this.tokens.add(token);
}
if (!token.isEmpty())
this.markDirty();
}
public void pop() {
if (!this.enabled) return;
String last;
synchronized (this.tokens) {
last = this.tokens.removeLast();
}
if (!last.isEmpty())
this.markDirty();
}
public void replace(String token) {
if (!this.enabled) return;
String last;
synchronized (this.tokens) {
last = this.tokens.removeLast();
this.tokens.add(token);
}
if (!last.equals(token))
this.markDirty();
}
public void setEnabled(boolean enabled) {
if (this.enabled && !enabled) {
this.thread = NULL_THREAD_REF;
synchronized (this.tokens) {
this.tokens.clear();
}
this.markDirty();
}
this.enabled = enabled;
}
protected void markDirty() {
assert this.activity != null;
assert this.textView != null;
if (this.updating) return;
this.updating = true;
this.activity.runOnUiThread(() -> {
String debugText;
synchronized (this.tokens) {
StringBuilder debug = this.debug;
debug.setLength(0);
boolean first = true;
for (String text : this.tokens) {
if (text.isEmpty()) continue;
if (first) first = false;
else debug.append(" > ");
debug.append(text);
}
debugText = debug.toString();
}
this.updating = false;
this.textView.setText(debugText);
});
}
@NonNull
public static NoodleDebug getNoodleDebug() {
NoodleDebug noodleDebug = THREAD_NOODLE.get();
if (noodleDebug == null) return NULL;
if (noodleDebug.thread.get() != Thread.currentThread() ||
noodleDebug.activity.isDestroyed()) {
THREAD_NOODLE.remove();
return NULL;
}
return noodleDebug;
}
}

@ -15,12 +15,13 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
app:layout_constraintTop_toTopOf="parent">
<!-- FrameLayout is the best way to fix blurring -->
<FrameLayout
android:id="@+id/blur_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/module_list"
android:layout_width="match_parent"
@ -36,6 +37,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/action_bar_padding"
android:layout_width="match_parent"
@ -44,31 +46,31 @@
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_bar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/action_bar_blur" />
<TextView
<!--<TextView
android:id="@+id/noodle_debug"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/action_bar_blur" />
app:layout_constraintTop_toBottomOf="@+id/action_bar_blur" />-->
<LinearLayout
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginTop="8dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="8dp"
android:gravity="right"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_fitsSystemWindowsInsets="bottom"
tools:ignore="RtlHardcoded">
<!--
@ -77,16 +79,17 @@
-->
<com.google.android.material.card.MaterialCardView
android:id="@+id/search_card"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:shape="ring"
android:layout_gravity="center"
android:background="@null"
android:shape="ring"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="0dp"
app:cardPreventCornerOverlap="true"
app:strokeColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeWidth="0dp">
<androidx.appcompat.widget.SearchView
android:id="@+id/search_bar"
android:layout_width="match_parent"

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----

@ -205,13 +205,16 @@
<string name="transparent_theme_dialogue_message">Transparent themes may have some inconsistencies and may not work on all ROMs. In additon, monet and blur will be disabled. You can change back at any time.</string>
<string name="custom_repo_always_on">Custom repos are always on until you remove them.</string>
<string name="sentry_dialogue_message">We encountered an error! Please help us improve the app
by adding some information about the error below. Name and email are optional.</string>
<string name="sentry_dialogue_title">Oops! Something went wrong.</string>
by adding some information about the error below.\nName and email are optional but will
allow us to contact you if needed for more information.</string>
<string name="sentry_dialogue_title">Oops! Looks like the app closed unexpectedly.</string>
<string name="name">Name</string>
<string name="email">Email</string>
<string name="additional_info">Tell us what happened</string>
<string name="submit">Submit</string>
<string name="sentry_dialogue_failed_toast">Could not submit feedback</string>
<string name="sentry_dialogue_success">Submitted feedback</string>
<string name="sentry_dialogue_no_description">Please provide a description/comment for the issue</string>
<string name="sentry_dialogue_failed_toast">Could not submit feedback due to an error</string>
<string name="sentry_dialogue_success">Submitted feedback successfully. We\'ll review it
shortly</string>
<string name="sentry_dialogue_no_description">Could not submit feedback as no
description was provided</string>
</resources>

@ -6,4 +6,22 @@
<certificates src="@raw/androidacy_root_ca" />
</trust-anchors>
</domain-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">github.com</domain>
<trust-anchors>
<certificates src="@raw/gh_root_ca" />
</trust-anchors>
</domain-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">githubusercontent.com</domain>
<trust-anchors>
<certificates src="@raw/gh_root_ca" />
</trust-anchors>
</domain-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">gstatic.com</domain>
<trust-anchors>
<certificates src="@raw/gstatic_root_ca" />
</trust-anchors>
</domain-config>
</network-security-config>

@ -3,16 +3,12 @@ package com.fox2code.mmm.sentry;
import static io.sentry.TypeCheckHint.SENTRY_TYPE_CHECK_HINT;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.util.Log;
import com.fox2code.mmm.BuildConfig;
import com.fox2code.mmm.MainActivity;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.androidacy.AndroidacyUtil;
@ -121,31 +117,10 @@ public class SentryMain {
// On uncaught exception, set the lastEventId in private sentry preferences
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
SentryId lastEventId = Sentry.captureException(throwable);
SharedPreferences.Editor editor = mainApplication.getSharedPreferences("sentry", 0).edit();
SharedPreferences.Editor editor = mainApplication.getSharedPreferences(
"sentry", Context.MODE_PRIVATE).edit();
editor.putString("lastExitReason", "crash");
editor.apply();
// Start a new instance of the main activity
// The intent flags ensure that the activity is started as a new task
// and that any existing task is cleared before the activity is started
// This ensures that the activity stack is cleared and the app is restarted
// from the root activity
Intent intent = new Intent(mainApplication, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Set an alarm to restart the app one second after it is killed
// This is necessary because the app is killed before the intent is started
// and the intent is ignored if the app is not running
PendingIntent pendingIntent;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
pendingIntent = PendingIntent.getActivity(mainApplication, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getActivity(mainApplication, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
AlarmManager alarmManager = (AlarmManager) mainApplication.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingIntent);
}
// Kill the app
System.exit(2);
});

Loading…
Cancel
Save