various tweaks

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/267/head
androidacy-user 1 year ago
parent 30d77941ac
commit 01214cf7f2

@ -54,7 +54,8 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
private static final String timeFormatString = "dd MMM yyyy"; // Example: 13 july 2001
private static final Shell.Builder shellBuilder;
private static final long secret;
@SuppressLint("RestrictedApi") // Use FoxProcess wrapper helper.
@SuppressLint("RestrictedApi")
// Use FoxProcess wrapper helper.
private static final boolean wrapped = !FoxProcessExt.isRootLoader();
private static Locale timeFormatLocale = Resources.getSystem().getConfiguration().locale;
private static SimpleDateFormat timeFormat = new SimpleDateFormat(timeFormatString, timeFormatLocale);
@ -63,7 +64,6 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
@SuppressLint("StaticFieldLeak")
private static MainApplication INSTANCE;
private static boolean firstBoot;
private static boolean loadSentryInitialized;
static {
Shell.setDefaultBuilder(shellBuilder = Shell.Builder.create().setFlags(Shell.FLAG_REDIRECT_STDERR).setTimeout(10).setInitializers(InstallerInitializer.class));
@ -142,7 +142,8 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
}
public static boolean isDeveloper() {
if (BuildConfig.DEBUG) return true;
if (BuildConfig.DEBUG)
return true;
return getSharedPreferences().getBoolean("developer", false);
}
@ -171,9 +172,7 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
}
public static boolean isCrashReportingEnabled() {
return SentryMain.IS_SENTRY_INSTALLED &&
getSharedPreferences().getBoolean("pref_crash_reporting",
BuildConfig.DEFAULT_ENABLE_CRASH_REPORTING);
return SentryMain.IS_SENTRY_INSTALLED && getSharedPreferences().getBoolean("pref_crash_reporting", BuildConfig.DEFAULT_ENABLE_CRASH_REPORTING);
}
public static SharedPreferences getBootSharedPreferences() {
@ -194,7 +193,8 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
}
public Markwon getMarkwon() {
if (this.markwon != null) return this.markwon;
if (this.markwon != null)
return this.markwon;
FoxThemeWrapper contextThemeWrapper = this.markwonThemeContext;
if (contextThemeWrapper == null) {
contextThemeWrapper = this.markwonThemeContext = new FoxThemeWrapper(this, this.managerThemeResId);
@ -276,7 +276,8 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
@Override
public void onCreate() {
if (INSTANCE == null) INSTANCE = this;
if (INSTANCE == null)
INSTANCE = this;
relPackageName = this.getPackageName();
super.onCreate();
SharedPreferences sharedPreferences = MainApplication.getSharedPreferences();
@ -362,24 +363,30 @@ public class MainApplication extends FoxApplication implements androidx.work.Con
String[] children = cacheDir.list();
if (children != null) {
for (String s : children) {
if (BuildConfig.DEBUG) Log.w("MainApplication", "Deleting " + s);
if (BuildConfig.DEBUG)
Log.w("MainApplication", "Deleting " + s);
if (!s.equals("lib")) {
if (!new File(cacheDir, s).delete()) {
if (BuildConfig.DEBUG) Log.w("MainApplication", "Failed to delete " + s);
if (BuildConfig.DEBUG)
Log.w("MainApplication", "Failed to delete " + s);
}
}
}
}
}
if (BuildConfig.DEBUG) Log.w("MainApplication", "Deleting cache dir");
if (BuildConfig.DEBUG)
Log.w("MainApplication", "Deleting cache dir");
this.deleteSharedPreferences("mmm_boot");
this.deleteSharedPreferences("mmm");
this.deleteSharedPreferences("sentry");
this.deleteSharedPreferences("androidacy");
if (BuildConfig.DEBUG) Log.w("MainApplication", "Deleting shared prefs");
if (BuildConfig.DEBUG)
Log.w("MainApplication", "Deleting shared prefs");
this.getPackageManager().clearPackagePreferredActivities(this.getPackageName());
if (BuildConfig.DEBUG) Log.w("MainApplication", "Done clearing app data");
} catch (Exception e) {
if (BuildConfig.DEBUG)
Log.w("MainApplication", "Done clearing app data");
} catch (
Exception e) {
Log.e("MainApplication", "Failed to clear app data", e);
}
}

@ -1,7 +1,9 @@
package com.fox2code.mmm.androidacy;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Looper;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
@ -26,6 +28,8 @@ import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@ -64,7 +68,8 @@ public final class AndroidacyRepoData extends RepoData {
if (!modulesJson.createNewFile()) {
throw new IOException("Failed to create modules.json");
}
} catch (IOException e) {
} catch (
IOException e) {
e.printStackTrace();
}
}
@ -144,7 +149,8 @@ public final class AndroidacyRepoData extends RepoData {
String deviceId = generateDeviceId();
try {
Http.doHttpGet("https://" + this.host + "/auth/me?token=" + token + "&device_id=" + deviceId, false);
} catch (HttpException e) {
} catch (
HttpException e) {
if (e.getErrorCode() == 401) {
Log.w(TAG, "Invalid token, resetting...");
// Remove saved preference
@ -159,6 +165,7 @@ public final class AndroidacyRepoData extends RepoData {
return true;
}
@SuppressLint("RestrictedApi")
@Override
protected boolean prepare() throws NoSuchAlgorithmException {
// If ANDROIDACY_CLIENT_ID is not set or is empty, disable this repo and return
@ -168,28 +175,44 @@ public final class AndroidacyRepoData extends RepoData {
editor.apply();
return false;
}
if (Http.needCaptchaAndroidacy()) return false;
if (Http.needCaptchaAndroidacy())
return false;
// Implementation details discussed on telegram
// First, ping the server to check if it's alive
try {
Http.doHttpGet("https://" + this.host + "/ping", false);
} catch (Exception e) {
HttpURLConnection connection = (HttpURLConnection) new URL("https://" + this.host + "/ping").openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
connection.connect();
if (connection.getResponseCode() != 200 && connection.getResponseCode() != 204) {
// If it's a 400, the app is probably outdated. Show a snackbar suggesting user update app and webview
if (connection.getResponseCode() == 400) {
// Show a dialog using androidacy_update_needed string
new MaterialAlertDialogBuilder(MainApplication.getINSTANCE())
.setTitle(R.string.androidacy_update_needed)
.setMessage(R.string.androidacy_update_needed_message)
.setPositiveButton(R.string.update, (dialog, which) -> {
// Open the app's page on the Play Store
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://github.com/Fox2Code/FoxMagiskModuleManager/releases/latest"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApplication.getINSTANCE().startActivity(intent);
})
.setNegativeButton(R.string.cancel, null)
.show();
}
return false;
}
} catch (
Exception e) {
Log.e(TAG, "Failed to ping server", e);
// Inform user
Looper.prepare();
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(MainApplication.getINSTANCE().getBaseContext());
builder.setTitle("Androidacy Server Down");
builder.setMessage("The Androidacy server is down. Unfortunately, this means that you" +
" will not be able to download or view modules from the Androidacy repository" +
". Please try again later.");
builder.setPositiveButton("OK", (dialog, which) -> dialog.dismiss());
builder.show();
Looper.loop();
return false;
}
String deviceId = generateDeviceId();
long time = System.currentTimeMillis();
if (this.androidacyBlockade > time) return true; // fake it till you make it. Basically,
if (this.androidacyBlockade > time)
return true; // fake it till you make it. Basically,
// don'e fail just becaue we're rate limited. API and web rate limits are different.
this.androidacyBlockade = time + 30_000L;
try {
@ -206,7 +229,8 @@ public final class AndroidacyRepoData extends RepoData {
}
this.token = null;
}
} catch (IOException e) {
} catch (
IOException e) {
if (HttpException.shouldTimeout(e)) {
Log.e(TAG, "We are being rate limited!", e);
this.androidacyBlockade = time + 3_600_000L;
@ -222,7 +246,8 @@ public final class AndroidacyRepoData extends RepoData {
try {
JSONObject jsonObject = new JSONObject(token);
token = jsonObject.getString("token");
} catch (JSONException e) {
} catch (
JSONException e) {
Log.e(TAG, "Failed to parse token", e);
// Show a toast
Toast.makeText(MainApplication.getINSTANCE(), R.string.androidacy_failed_to_parse_token, Toast.LENGTH_LONG).show();
@ -239,7 +264,8 @@ public final class AndroidacyRepoData extends RepoData {
SharedPreferences.Editor editor = MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit();
editor.putString("pref_androidacy_api_token", token);
editor.apply();
} catch (Exception e) {
} catch (
Exception e) {
if (HttpException.shouldTimeout(e)) {
Log.e(TAG, "We are being rate limited!", e);
this.androidacyBlockade = time + 3_600_000L;
@ -324,7 +350,8 @@ public final class AndroidacyRepoData extends RepoData {
moduleInfo.minMagisk = // Allow 24.1 to mean 24100
(Integer.parseInt(minMagisk.substring(0, c)) * 1000) + (Integer.parseInt(minMagisk.substring(c + 1)) * 100);
}
} catch (Exception e) {
} catch (
Exception e) {
moduleInfo.minMagisk = 0;
}
moduleInfo.needRamdisk = jsonObject.optBoolean("needRamdisk", false);
@ -370,13 +397,13 @@ public final class AndroidacyRepoData extends RepoData {
@Override
public String getUrl() throws NoSuchAlgorithmException {
return this.token == null ? this.url :
this.url + "?token=" + this.token + "&v=" + BuildConfig.VERSION_CODE + "&c=" + BuildConfig.VERSION_NAME + "&device_id=" + generateDeviceId();
return this.token == null ? this.url : this.url + "?token=" + this.token + "&v=" + BuildConfig.VERSION_CODE + "&c=" + BuildConfig.VERSION_NAME + "&device_id=" + generateDeviceId();
}
private String injectToken(String url) throws NoSuchAlgorithmException {
// Do not inject token for non Androidacy urls
if (!AndroidacyUtil.isAndroidacyLink(url)) return url;
if (!AndroidacyUtil.isAndroidacyLink(url))
return url;
if (this.testMode) {
if (url.startsWith("https://production-api.androidacy.com/")) {
Log.e(TAG, "Got non test mode url: " + AndroidacyUtil.hideToken(url));

@ -19,7 +19,6 @@ import com.fox2code.mmm.MainActivity;
import com.fox2code.mmm.MainApplication;
import com.fox2code.mmm.androidacy.AndroidacyUtil;
import com.fox2code.mmm.installer.InstallerInitializer;
import com.fox2code.mmm.repo.RepoManager;
import com.google.net.cronet.okhttptransport.CronetInterceptor;
import org.chromium.net.CronetEngine;
@ -78,7 +77,8 @@ public class Http {
System.err.flush();
try {
Os.kill(Os.getpid(), 9);
} catch (ErrnoException e) {
} catch (
ErrnoException e) {
System.exit(9);
}
throw error;
@ -88,7 +88,8 @@ public class Http {
cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.flush(); // Make sure the instance work
} catch (Throwable t) {
} catch (
Throwable t) {
cookieManager = null;
Log.e(TAG, "No WebView support!", t);
}
@ -111,7 +112,9 @@ public class Http {
httpclientBuilder.dns(dns);
httpclientBuilder.cookieJar(new CDNCookieJar());
dns = new DnsOverHttps.Builder().client(httpclientBuilder.build()).url(Objects.requireNonNull(HttpUrl.parse("https://cloudflare-dns.com/dns-query"))).bootstrapDnsHosts(cloudflareBootstrap).resolvePrivateAddresses(true).build();
} catch (UnknownHostException | RuntimeException e) {
} catch (
UnknownHostException |
RuntimeException e) {
Log.e(TAG, "Failed to init DoH", e);
}
httpclientBuilder.cookieJar(CookieJar.NO_COOKIES);
@ -165,7 +168,8 @@ public class Http {
builder.addQuicHint("sentry.io", 443, 443);
CronetEngine engine = builder.build();
httpclientBuilder.addInterceptor(CronetInterceptor.newBuilder(engine).build());
} catch (Exception e) {
} catch (
Exception e) {
Log.e(TAG, "Failed to init cronet", e);
// Gracefully fallback to okhttp
}
@ -205,16 +209,6 @@ public class Http {
}
}
private static void checkNeedBlockAndroidacyRequest(String url) throws IOException {
if (!RepoManager.isAndroidacyRepoEnabled()) {
if (AndroidacyUtil.isAndroidacyLink(url)) {
throw new IOException("Androidacy repo is disabled, blocking url: " + url);
}
} else if (needCaptchaAndroidacy() && AndroidacyUtil.isAndroidacyLink(url)) {
throw new HttpException("Androidacy require the user to solve a captcha", 403);
}
}
public static boolean needCaptchaAndroidacy() {
return needCaptchaAndroidacyHost != null;
}
@ -246,7 +240,8 @@ public class Http {
// Use cache api if used cached response
if (response.code() == 304) {
response = response.cacheResponse();
if (response != null) responseBody = response.body();
if (response != null)
responseBody = response.body();
}
return responseBody.bytes();
}
@ -257,7 +252,8 @@ public class Http {
@SuppressWarnings("resource")
private static Object doHttpPostRaw(String url, String data, boolean allowCache) throws IOException {
if (BuildConfig.DEBUG) Log.i(TAG, "POST " + url + " " + data);
if (BuildConfig.DEBUG)
Log.i(TAG, "POST " + url + " " + data);
Response response;
response = (allowCache ? getHttpClientWithCache() : getHttpClient()).newCall(new Request.Builder().url(url).post(JsonRequestBody.from(data)).header("Content-Type", "application/json").build()).execute();
if (response.isRedirect()) {
@ -274,13 +270,15 @@ public class Http {
// Use cache api if used cached response
if (response.code() == 304) {
response = response.cacheResponse();
if (response != null) responseBody = response.body();
if (response != null)
responseBody = response.body();
}
return responseBody.bytes();
}
public static byte[] doHttpGet(String url, ProgressListener progressListener) throws IOException {
if (BuildConfig.DEBUG) Log.i("Http", "GET " + url.split("\\?")[0]);
if (BuildConfig.DEBUG)
Log.i("Http", "GET " + url.split("\\?")[0]);
Response response = getHttpClient().newCall(new Request.Builder().url(url).get().build()).execute();
if (response.code() != 200 && response.code() != 204) {
Log.e(TAG, "Failed to fetch " + url + ", code: " + response.code());
@ -304,7 +302,8 @@ public class Http {
progressListener.onUpdate(0, (int) (target / divider), false);
while (true) {
int read = inputStream.read(buff);
if (read == -1) break;
if (read == -1)
break;
byteArrayOutputStream.write(buff, 0, read);
downloaded += read;
currentUpdate = System.currentTimeMillis();
@ -420,11 +419,14 @@ public class Http {
@NonNull
@Override
public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) {
if (!httpUrl.isHttps()) return Collections.emptyList();
if (!httpUrl.isHttps())
return Collections.emptyList();
if (this.androidacySupport && httpUrl.host().endsWith(".androidacy.com")) {
if (this.cookieManager == null) return this.androidacyCookies;
if (this.cookieManager == null)
return this.androidacyCookies;
String cookies = this.cookieManager.getCookie(httpUrl.uri().toString());
if (cookies == null || cookies.isEmpty()) return Collections.emptyList();
if (cookies == null || cookies.isEmpty())
return Collections.emptyList();
String[] splitCookies = cookies.split(";");
ArrayList<Cookie> cookieList = new ArrayList<>(splitCookies.length);
for (String cookie : splitCookies) {
@ -438,7 +440,8 @@ public class Http {
@Override
public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> cookies) {
if (!httpUrl.isHttps()) return;
if (!httpUrl.isHttps())
return;
if (this.androidacySupport && httpUrl.host().endsWith(".androidacy.com")) {
if (this.cookieManager == null) {
if (httpUrl.host().equals(".androidacy.com") || !cookies.isEmpty())
@ -496,19 +499,22 @@ public class Http {
@NonNull
private static String toString(@NonNull List<InetAddress> inetAddresses) {
if (inetAddresses.isEmpty()) return "";
if (inetAddresses.isEmpty())
return "";
Iterator<InetAddress> inetAddressIterator = inetAddresses.iterator();
StringBuilder stringBuilder = new StringBuilder();
while (true) {
stringBuilder.append(inetAddressIterator.next().getHostAddress());
if (!inetAddressIterator.hasNext()) return stringBuilder.toString();
if (!inetAddressIterator.hasNext())
return stringBuilder.toString();
stringBuilder.append("|");
}
}
@NonNull
private static List<InetAddress> fromString(@NonNull String string) throws UnknownHostException {
if (string.isEmpty()) return Collections.emptyList();
if (string.isEmpty())
return Collections.emptyList();
String[] strings = string.split("\\|");
ArrayList<InetAddress> inetAddresses = new ArrayList<>(strings.length);
for (String address : strings) {
@ -524,20 +530,24 @@ public class Http {
List<InetAddress> addresses;
synchronized (this.fallbackCache) {
addresses = this.fallbackCache.get(s);
if (addresses != null) return addresses;
if (addresses != null)
return addresses;
try {
addresses = this.parent.lookup(s);
if (addresses.isEmpty() || addresses.get(0).isLoopbackAddress())
throw new UnknownHostException(s);
this.fallbackCache.put(s, addresses);
this.sharedPreferences.edit().putString(s.replace('.', '_'), toString(addresses)).apply();
} catch (UnknownHostException e) {
} catch (
UnknownHostException e) {
String key = this.sharedPreferences.getString(s.replace('.', '_'), "");
if (key.isEmpty()) throw e;
if (key.isEmpty())
throw e;
try {
addresses = fromString(key);
this.fallbackCache.put(s, addresses);
} catch (UnknownHostException e2) {
} catch (
UnknownHostException e2) {
this.sharedPreferences.edit().remove(s.replace('.', '_')).apply();
throw e;
}

@ -248,5 +248,12 @@
<string name="debug_build">This is a debug build. Expect some bugs and worse performance.</string>
<string name="androidacy_repo_name">Androidacy Repo</string>
<string name="magisk_alt_repo_name">Magisk Alt Repo</string>
<string name="repo_enabled_changed">You\'ve enabled or disabled a repo. Please refresh the module list or restart the app.</string><string name="finish">Finish</string><string name="setup_theme">Choose a theme</string><string name="setup_theme_header">Choose a theme</string><string name="setup_theme_system">System theme</string><string name="setup_theme_light">Light theme</string><string name="setup_theme_dark">Dark theme</string><string name="setup_theme_black">AMOLED Black theme</string><string name="setup_theme_transparent_light">Transparent light theme - will disable monet and blur!</string><string name="setup_theme_button">Choose a theme</string><string name="theme">Theme</string><string name="theme_system">System</string><string name="theme_dark">Dark</string><string name="theme_black">AMOLED Black</string><string name="theme_transparent_light">Light (transparency)</string><string name="theme_light">Light</string>
<string name="repo_enabled_changed">You\'ve enabled or disabled a repo. Please refresh the module list or restart the app.</string><string name="finish">Finish</string><string name="setup_theme">Choose a theme</string><string name="setup_theme_header">Choose a theme</string><string name="setup_theme_system">System theme</string><string name="setup_theme_light">Light theme</string><string name="setup_theme_dark">Dark theme</string><string name="setup_theme_black">AMOLED Black theme</string><string name="setup_theme_transparent_light">Transparent light theme - will disable monet and blur!</string><string name="setup_theme_button">Choose a theme</string><string name="theme">Theme</string><string name="theme_system">System</string>
<string name="theme_dark">Dark</string>
<string name="theme_black">AMOLED Black</string>
<string name="theme_transparent_light">Light (transparency)</string>
<string name="theme_light">Light</string>
<string name="androidacy_update_needed">This app is outdated.</string>
<string name="androidacy_update_needed_message">Please update the app to the latest version.</string>
<string name="androidacy_webview_update_required">Your webview is outdated! Please update it.</string>
</resources>

Loading…
Cancel
Save