moduleInfoIterator = this.moduleHashMap.values().iterator();
while (moduleInfoIterator.hasNext()) {
@@ -240,13 +254,6 @@ public final class AndroidacyRepoData extends RepoData {
return newModules;
}
- private static String filterURL(String url) {
- if (url == null || url.isEmpty() || PropUtils.isInvalidURL(url)) {
- return null;
- }
- return url;
- }
-
@Override
public void storeMetadata(RepoModule repoModule, byte[] data) {
}
@@ -254,34 +261,30 @@ public final class AndroidacyRepoData extends RepoData {
@Override
public boolean tryLoadMetadata(RepoModule repoModule) {
if (this.moduleHashMap.containsKey(repoModule.id)) {
- repoModule.moduleInfo.flags &=
- ~ModuleInfo.FLAG_METADATA_INVALID;
+ repoModule.moduleInfo.flags &= ~ModuleInfo.FLAG_METADATA_INVALID;
return true;
}
- repoModule.moduleInfo.flags |=
- ModuleInfo.FLAG_METADATA_INVALID;
+ repoModule.moduleInfo.flags |= ModuleInfo.FLAG_METADATA_INVALID;
return false;
}
@Override
public String getUrl() {
- return this.token == null ? this.url :
- this.url + "?token=" + this.token;
+ return this.token == null ? this.url : this.url + "?token=" + this.token;
}
private String injectToken(String url) {
// 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://api.androidacy.com/")) {
+ if (url.startsWith("https://production-api.androidacy.com/")) {
Log.e(TAG, "Got non test mode url: " + AndroidacyUtil.hideToken(url));
url = "https://staging-api.androidacy.com/" + url.substring(27);
}
} else {
if (url.startsWith("https://staging-api.androidacy.com/")) {
Log.e(TAG, "Got test mode url: " + AndroidacyUtil.hideToken(url));
- url = "https://api.androidacy.com/" + url.substring(35);
+ url = "https://production-api.androidacy.com/" + url.substring(35);
}
}
String token = "token=" + this.token;
@@ -307,9 +310,8 @@ public final class AndroidacyRepoData extends RepoData {
void setToken(String token) {
if (Http.hasWebView()) {
- CookieManager.getInstance().setCookie("https://.androidacy.com/",
- "USER=" + token + "; expires=Fri, 31 Dec 9999 23:59:59 GMT;" +
- " path=/; secure; domain=.androidacy.com");
+ // TODO: Figure out why this is needed
+ CookieManager.getInstance().setCookie("https://.androidacy.com/", "USER=" + token + "; expires=Fri, 31 Dec 9999 23:59:59 GMT;" + " path=/; secure; domain=.androidacy.com");
this.token = token;
}
}
diff --git a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java
index 6846921..cff88e1 100644
--- a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java
+++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java
@@ -53,6 +53,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
+@SuppressWarnings("IOStreamConstructor")
public class InstallerActivity extends FoxActivity {
private static final String TAG = "InstallerActivity";
public LinearProgressIndicator progressIndicator;
@@ -156,8 +157,9 @@ public class InstallerActivity extends FoxActivity {
!new SuFile(moduleCache.getAbsolutePath()).delete())
Log.e(TAG, "Failed to delete module cache");
String errMessage = "Failed to download module zip";
+ // Set this to the error message if it's a HTTP error
byte[] rawModule;
- boolean androidacyBlame = false; // In case Androidacy mess-up again...
+ boolean androidacyBlame = false; // In case Androidacy mess-up again... yeah screw you too jk jk
try {
Log.i(TAG, (urlMode ? "Downloading: " : "Loading: ") + target);
rawModule = urlMode ? Http.doHttpGet(target, (progress, max, done) -> {
@@ -254,11 +256,9 @@ public class InstallerActivity extends FoxActivity {
} catch (IOException e) {
Log.e(TAG, errMessage, e);
if (androidacyBlame) {
- this.installerTerminal.addLine(
- "! Note: The following error is probably an Androidacy backend error");
+ errMessage += " (" + e.getLocalizedMessage() + ")";
}
- this.setInstallStateFinished(false,
- "! " + errMessage, "");
+ this.setInstallStateFinished(false, errMessage, null);
} catch (OutOfMemoryError e) {
//noinspection UnusedAssignment (Important to avoid OutOfMemoryError)
rawModule = null; // Because reference is kept when calling setInstallStateFinished
diff --git a/app/src/main/java/com/fox2code/mmm/utils/Http.java b/app/src/main/java/com/fox2code/mmm/utils/Http.java
index acc2976..6ecc265 100644
--- a/app/src/main/java/com/fox2code/mmm/utils/Http.java
+++ b/app/src/main/java/com/fox2code/mmm/utils/Http.java
@@ -36,7 +36,6 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
-import io.sentry.android.okhttp.SentryOkHttpInterceptor;
import okhttp3.Cache;
import okhttp3.Cookie;
import okhttp3.CookieJar;
@@ -100,7 +99,7 @@ public class Http {
httpclientBuilder.proxy(Proxy.NO_PROXY); // Do not use system proxy
Dns dns = Dns.SYSTEM;
try {
- InetAddress[] cloudflareBootstrap = new InetAddress[] {
+ InetAddress[] cloudflareBootstrap = new InetAddress[]{
InetAddress.getByName("162.159.36.1"),
InetAddress.getByName("162.159.46.1"),
InetAddress.getByName("1.1.1.1"),
@@ -120,18 +119,18 @@ 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")))
+ 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);
// User-Agent format was agreed on telegram
if (hasWebView) {
- androidacyUA = WebSettings.getDefaultUserAgent(mainApplication).replace("; wv", "")
- + " FoxMmm/" + BuildConfig.VERSION_CODE;
+ androidacyUA = WebSettings.getDefaultUserAgent(mainApplication).replace("wv", "FoxMmm" +
+ "/" + BuildConfig.VERSION_CODE);
} else {
- androidacyUA = "Mozilla/5.0 (Linux; Android " + Build.VERSION.RELEASE + "; " + Build.DEVICE +")" +
+ androidacyUA = "Mozilla/5.0 (Linux; Android " + Build.VERSION.RELEASE + "; " + Build.DEVICE + ")" +
" AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Mobile Safari/537.36"
+ " FoxMmm/" + BuildConfig.VERSION_CODE;
}
@@ -197,7 +196,7 @@ public class Http {
}
@SuppressWarnings("resource")
- public static byte[] doHttpGet(String url,boolean allowCache) throws IOException {
+ public static byte[] doHttpGet(String url, boolean allowCache) throws IOException {
if (!RepoManager.isAndroidacyRepoEnabled() &&
AndroidacyUtil.isAndroidacyLink(url)) {
throw new IOException("Androidacy repo is disabled, blocking url: " + url);
@@ -208,19 +207,19 @@ public class Http {
// 200/204 == success, 304 == cache valid
if (response.code() != 200 && response.code() != 204 &&
(response.code() != 304 || !allowCache)) {
- throw new IOException("Received error code: "+ response.code());
+ throw new IOException("Received error code: " + response.code());
}
ResponseBody responseBody = response.body();
// Use cache api if used cached response
- if (responseBody == null && response.code() == 304) {
+ if (response.code() == 304) {
response = response.cacheResponse();
if (response != null)
responseBody = response.body();
}
- return responseBody == null ? new byte[0] : responseBody.bytes();
+ return responseBody.bytes();
}
- public static byte[] doHttpPost(String url,String data,boolean allowCache) throws IOException {
+ public static byte[] doHttpPost(String url, String data, boolean allowCache) throws IOException {
return (byte[]) doHttpPostRaw(url, data, allowCache, false);
}
@@ -229,8 +228,8 @@ public class Http {
}
@SuppressWarnings("resource")
- private static Object doHttpPostRaw(String url,String data, boolean allowCache,
- boolean isRedirect) throws IOException {
+ private static Object doHttpPostRaw(String url, String data, boolean allowCache,
+ boolean isRedirect) throws IOException {
if (!RepoManager.isAndroidacyRepoEnabled() &&
AndroidacyUtil.isAndroidacyLink(url)) {
throw new IOException("Androidacy repo is disabled, blocking url: " + url);
@@ -246,20 +245,20 @@ public class Http {
// 200/204 == success, 304 == cache valid
if (response.code() != 200 && response.code() != 204 &&
(response.code() != 304 || !allowCache)) {
- throw new IOException("Received error code: "+ response.code());
+ throw new IOException("Received error code: " + response.code());
}
if (isRedirect) return url;
ResponseBody responseBody = response.body();
// Use cache api if used cached response
- if (responseBody == null && response.code() == 304) {
+ if (response.code() == 304) {
response = response.cacheResponse();
if (response != null)
responseBody = response.body();
}
- return responseBody == null ? new byte[0] : responseBody.bytes();
+ return responseBody.bytes();
}
- public static byte[] doHttpGet(String url,ProgressListener progressListener) throws IOException {
+ public static byte[] doHttpGet(String url, ProgressListener progressListener) throws IOException {
Log.d("Http", "Progress URL: " + url);
if (!RepoManager.isAndroidacyRepoEnabled() &&
AndroidacyUtil.isAndroidacyLink(url)) {
@@ -268,7 +267,7 @@ public class Http {
Response response = getHttpClient().newCall(
new Request.Builder().url(url).get().build()).execute();
if (response.code() != 200 && response.code() != 204) {
- throw new IOException("Received error code: "+ response.code());
+ throw new IOException("Received error code: " + response.code());
}
ResponseBody responseBody = Objects.requireNonNull(response.body());
InputStream inputStream = responseBody.byteStream();
@@ -287,7 +286,7 @@ 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();
@@ -325,15 +324,65 @@ public class Http {
return cookieJar.getAndroidacyCookies(url);
}
+ public static boolean hasWebView() {
+ return hasWebView;
+ }
+
+ /**
+ * Change URL to appropriate url and force Magisk link to use latest version.
+ */
+ public static String updateLink(String string) {
+ if (string.startsWith("https://cdn.jsdelivr.net/gh/Magisk-Modules-Repo/")) {
+ String tmp = string.substring(48);
+ int start = tmp.lastIndexOf('@'),
+ end = tmp.lastIndexOf('/');
+ if ((end - 8) <= start) return string; // Skip if not a commit id
+ return "https://raw.githubusercontent.com/" +
+ tmp.substring(0, start) + "/master" + string.substring(end);
+ }
+ if (string.startsWith("https://github.com/Magisk-Modules-Repo/")) {
+ int i = string.lastIndexOf("/archive/");
+ if (i != -1 && string.indexOf('/', i + 9) == -1)
+ return string.substring(0, i + 9) + "master.zip";
+ }
+ return string;
+ }
+
+ /**
+ * Change GitHub user-content url to jsdelivr url
+ * (Unused but kept as a documentation)
+ */
+ public static String cdnIfyLink(String string) {
+ if (string.startsWith("https://raw.githubusercontent.com/")) {
+ String[] tokens = string.substring(34).split("/", 4);
+ if (tokens.length != 4) return string;
+ return "https://cdn.jsdelivr.net/gh/" +
+ tokens[0] + "/" + tokens[1] + "@" + tokens[2] + "/" + tokens[3];
+ }
+ if (string.startsWith("https://github.com/")) {
+ int i = string.lastIndexOf("/archive/");
+ if (i == -1 || string.indexOf('/', i + 9) != -1)
+ return string; // Not an archive link
+ String[] tokens = string.substring(19).split("/", 4);
+ return "https://cdn.jsdelivr.net/gh/" +
+ tokens[0] + "/" + tokens[1] + "@" + tokens[2] + "/" + tokens[3];
+ }
+ return string;
+ }
+
+ public interface ProgressListener {
+ void onUpdate(int downloaded, int total, boolean done);
+ }
+
/**
* Cookie jar that allow CDN cookies, reset on app relaunch
* Note: An argument can be made that it allow tracking but
* caching is a better attack vector for tracking, this system
* only exist to improve CDN response time, any other cookies
* that are not CDN related are just simply ignored.
- *
+ *
* Note: CDNCookies are only stored in RAM unlike https cache
- * */
+ */
private static class CDNCookieJar implements CookieJar {
private final HashMap cookieMap = new HashMap<>();
private final boolean androidacySupport;
@@ -425,17 +474,13 @@ public class Http {
}
}
- public interface ProgressListener {
- void onUpdate(int downloaded,int total, boolean done);
- }
-
/**
* FallBackDNS store successful DNS request to return them later
* can help make the app to work later when the current DNS system
* isn't functional or available.
- *
+ *
* Note: DNS Cache is stored in user data.
- * */
+ */
private static class FallBackDNS implements Dns {
private final Dns parent;
private final SharedPreferences sharedPreferences;
@@ -450,6 +495,31 @@ public class Http {
this.fallbackCache = new HashMap<>();
}
+ @NonNull
+ private static String toString(@NonNull List inetAddresses) {
+ if (inetAddresses.isEmpty()) return "";
+ Iterator inetAddressIterator = inetAddresses.iterator();
+ StringBuilder stringBuilder = new StringBuilder();
+ while (true) {
+ stringBuilder.append(inetAddressIterator.next().getHostAddress());
+ if (!inetAddressIterator.hasNext())
+ return stringBuilder.toString();
+ stringBuilder.append("|");
+ }
+ }
+
+ @NonNull
+ private static List fromString(@NonNull String string)
+ throws UnknownHostException {
+ if (string.isEmpty()) return Collections.emptyList();
+ String[] strings = string.split("\\|");
+ ArrayList inetAddresses = new ArrayList<>(strings.length);
+ for (String address : strings) {
+ inetAddresses.add(InetAddress.getByName(address));
+ }
+ return inetAddresses;
+ }
+
@NonNull
@Override
public List lookup(@NonNull String s) throws UnknownHostException {
@@ -491,36 +561,16 @@ public class Http {
this.fallbackCache.clear();
}
}
-
- @NonNull
- private static String toString(@NonNull List inetAddresses) {
- if (inetAddresses.isEmpty()) return "";
- Iterator inetAddressIterator = inetAddresses.iterator();
- StringBuilder stringBuilder = new StringBuilder();
- while (true) {
- stringBuilder.append(inetAddressIterator.next().getHostAddress());
- if (!inetAddressIterator.hasNext())
- return stringBuilder.toString();
- stringBuilder.append("|");
- }
- }
-
- @NonNull
- private static List fromString(@NonNull String string)
- throws UnknownHostException {
- if (string.isEmpty()) return Collections.emptyList();
- String[] strings = string.split("\\|");
- ArrayList inetAddresses = new ArrayList<>(strings.length);
- for (String address : strings) {
- inetAddresses.add(InetAddress.getByName(address));
- }
- return inetAddresses;
- }
}
private static class JsonRequestBody extends RequestBody {
private static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json");
private static final JsonRequestBody EMPTY = new JsonRequestBody(new byte[0]);
+ final byte[] data;
+
+ private JsonRequestBody(byte[] data) {
+ this.data = data;
+ }
static JsonRequestBody from(String data) {
if (data == null || data.length() == 0) {
@@ -529,12 +579,6 @@ public class Http {
return new JsonRequestBody(data.getBytes(StandardCharsets.UTF_8));
}
- final byte[] data;
-
- private JsonRequestBody(byte[] data) {
- this.data = data;
- }
-
@Nullable
@Override
public MediaType contentType() {
@@ -551,50 +595,4 @@ public class Http {
bufferedSink.write(this.data);
}
}
-
- public static boolean hasWebView() {
- return hasWebView;
- }
-
- /**
- * Change URL to appropriate url and force Magisk link to use latest version.
- */
- public static String updateLink(String string) {
- if (string.startsWith("https://cdn.jsdelivr.net/gh/Magisk-Modules-Repo/")) {
- String tmp = string.substring(48);
- int start = tmp.lastIndexOf('@'),
- end = tmp.lastIndexOf('/');
- if ((end - 8) <= start) return string; // Skip if not a commit id
- return "https://raw.githubusercontent.com/" +
- tmp.substring(0, start) + "/master" + string.substring(end);
- }
- if (string.startsWith("https://github.com/Magisk-Modules-Repo/")) {
- int i = string.lastIndexOf("/archive/");
- if (i != -1 && string.indexOf('/', i + 9) == -1)
- return string.substring(0, i + 9) + "master.zip";
- }
- return string;
- }
-
- /**
- * Change GitHub user-content url to jsdelivr url
- * (Unused but kept as a documentation)
- */
- public static String cdnIfyLink(String string) {
- if (string.startsWith("https://raw.githubusercontent.com/")) {
- String[] tokens = string.substring(34).split("/", 4);
- if (tokens.length != 4) return string;
- return "https://cdn.jsdelivr.net/gh/" +
- tokens[0] + "/" + tokens[1] + "@" + tokens[2] + "/" + tokens[3];
- }
- if (string.startsWith("https://github.com/")) {
- int i = string.lastIndexOf("/archive/");
- if (i == -1 || string.indexOf('/', i + 9) != -1)
- return string; // Not an archive link
- String[] tokens = string.substring(19).split("/", 4);
- return "https://cdn.jsdelivr.net/gh/" +
- tokens[0] + "/" + tokens[1] + "@" + tokens[2] + "/" + tokens[3];
- }
- return string;
- }
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1358a5d..194914b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -176,4 +176,7 @@
The app needs to restart to apply this setting
Restart
App will be restarted to disable staging endpoint
+ Could not retrieve token from Androidacy. Please try again later.
+ Could not validate token for Androidacy. Please try again later.
+ Unable to contact Androidacy server. Check your connection and try again.
diff --git a/gradle.properties b/gradle.properties
index 2649381..5f80030 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=512m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
@@ -21,3 +21,4 @@ android.enableJetifier=true
# Fox builds props mods
org.gradle.parallel=true
android.enableR8.fullMode=true
+org.gradle.unsafe.configuration-cache=true