Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit 7136803

Browse files
author
mi007d
committed
2 parents ae93cfb + 7a6aa28 commit 7136803

File tree

8 files changed

+137
-32
lines changed

8 files changed

+137
-32
lines changed

app/src/main/java/com/fox2code/mmm/ActionButtonType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import androidx.annotation.DrawableRes;
1010
import androidx.appcompat.app.AlertDialog;
1111

12+
import com.fox2code.mmm.androidacy.AndroidacyUtil;
1213
import com.fox2code.mmm.compat.CompatActivity;
1314
import com.fox2code.mmm.compat.CompatDisplay;
1415
import com.fox2code.mmm.installer.InstallerInitializer;
@@ -160,7 +161,7 @@ public boolean doActionLong(ImageButton button, ModuleHolder moduleHolder) {
160161
public void doAction(ImageButton button, ModuleHolder moduleHolder) {
161162
String config = moduleHolder.getMainModuleConfig();
162163
if (config == null) return;
163-
if (config.startsWith("https://www.androidacy.com/")) {
164+
if (AndroidacyUtil.isAndroidacyLink(config)) {
164165
IntentHelper.openUrlAndroidacy(button.getContext(), config, true);
165166
} else {
166167
IntentHelper.openConfig(button.getContext(), config);

app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyActivity.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.net.Uri;
88
import android.os.Build;
99
import android.os.Bundle;
10+
import android.util.Log;
1011
import android.webkit.ValueCallback;
1112
import android.webkit.WebChromeClient;
1213
import android.webkit.WebResourceRequest;
@@ -33,6 +34,7 @@
3334
* Per Androidacy repo implementation agreement, no request of this WebView shall be modified.
3435
*/
3536
public class AndroidacyActivity extends CompatActivity {
37+
private static final String TAG = "AndroidacyActivity";
3638
private static final String REFERRER = "utm_source=FoxMMM&utm_medium=app";
3739

3840
static {
@@ -42,6 +44,7 @@ public class AndroidacyActivity extends CompatActivity {
4244
}
4345

4446
WebView webView;
47+
AndroidacyWebAPI androidacyWebAPI;
4548
boolean backOnResume;
4649

4750
@Override
@@ -51,16 +54,14 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5154
Intent intent = this.getIntent();
5255
Uri uri;
5356
if (!MainApplication.checkSecret(intent) ||
54-
(uri = intent.getData()) == null ||
55-
!uri.getHost().endsWith(".androidacy.com")) {
57+
(uri = intent.getData()) == null) {
58+
Log.w(TAG, "Impersonation detected");
5659
this.forceBackPressed();
5760
return;
5861
}
5962
String url = uri.toString();
60-
int i;
61-
if (!url.startsWith("https://") || // Checking twice
62-
(i = url.indexOf("/", 8)) == -1 ||
63-
!url.substring(8, i).endsWith(".androidacy.com")) {
63+
if (!AndroidacyUtil.isAndroidacyLink(url, uri)) {
64+
Log.w(TAG, "Calling non androidacy link in secure WebView: " + url);
6465
this.forceBackPressed();
6566
return;
6667
}
@@ -112,9 +113,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
112113
@Override
113114
public boolean shouldOverrideUrlLoading(
114115
@NonNull WebView view, @NonNull WebResourceRequest request) {
115-
// Don't open non andoridacy urls inside WebView
116+
// Don't open non Androidacy urls inside WebView
116117
if (request.isForMainFrame() && !(request.getUrl().getScheme().equals("intent") ||
117-
request.getUrl().getHost().endsWith(".androidacy.com"))) {
118+
AndroidacyUtil.isAndroidacyLink(request.getUrl()))) {
118119
IntentHelper.openUrl(view.getContext(), request.getUrl().toString());
119120
return true;
120121
}
@@ -159,7 +160,7 @@ public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathC
159160
return true;
160161
}
161162
});
162-
this.webView.addJavascriptInterface(
163+
this.webView.addJavascriptInterface(androidacyWebAPI =
163164
new AndroidacyWebAPI(this, allowInstall), "mmm");
164165
this.webView.loadUrl(url);
165166
}
@@ -180,6 +181,8 @@ protected void onResume() {
180181
if (this.backOnResume) {
181182
this.backOnResume = false;
182183
this.forceBackPressed();
184+
} else if (this.androidacyWebAPI != null) {
185+
this.androidacyWebAPI.consumedAction = false;
183186
}
184187
}
185188
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.fox2code.mmm.androidacy;
2+
3+
import android.net.Uri;
4+
5+
import androidx.annotation.NonNull;
6+
import androidx.annotation.Nullable;
7+
8+
public class AndroidacyUtil {
9+
public static boolean isAndroidacyLink(@Nullable Uri uri) {
10+
return uri != null && isAndroidacyLink(uri.toString(), uri);
11+
}
12+
13+
public static boolean isAndroidacyLink(@Nullable String url) {
14+
return url != null && isAndroidacyLink(url, Uri.parse(url));
15+
}
16+
17+
static boolean isAndroidacyLink(@NonNull String url,@NonNull Uri uri) {
18+
int i; // Check both string and Uri to mitigate parse exploit
19+
return url.startsWith("https://") &&
20+
(i = url.indexOf("/", 8)) != -1 &&
21+
url.substring(8, i).endsWith(".androidacy.com") &&
22+
uri.getHost().endsWith(".androidacy.com");
23+
}
24+
}

app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyWebAPI.java

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.fox2code.mmm.manager.ModuleInfo;
1414
import com.fox2code.mmm.manager.ModuleManager;
1515
import com.fox2code.mmm.utils.Files;
16+
import com.fox2code.mmm.utils.Hashes;
1617
import com.fox2code.mmm.utils.IntentHelper;
1718

1819
import java.io.File;
@@ -23,21 +24,30 @@ public class AndroidacyWebAPI {
2324
private static final String TAG = "AndroidacyWebAPI";
2425
private final AndroidacyActivity activity;
2526
private final boolean allowInstall;
27+
boolean consumedAction;
2628

2729
public AndroidacyWebAPI(AndroidacyActivity activity, boolean allowInstall) {
2830
this.activity = activity;
2931
this.allowInstall = allowInstall;
3032
}
3133

34+
public void forceQuitRaw(String error) {
35+
Toast.makeText(this.activity, error, Toast.LENGTH_LONG).show();
36+
this.activity.runOnUiThread(this.activity::forceBackPressed);
37+
this.activity.backOnResume = true; // Set backOnResume just in case
38+
}
39+
3240
@JavascriptInterface
3341
public void forceQuit(String error) {
34-
Toast.makeText(this.activity, error, Toast.LENGTH_LONG).show();
35-
this.activity.runOnUiThread(
36-
this.activity::forceBackPressed);
42+
if (this.consumedAction) return;
43+
this.consumedAction = true;
44+
this.forceQuitRaw(error);
3745
}
3846

3947
@JavascriptInterface
4048
public void cancel() {
49+
if (this.consumedAction) return;
50+
this.consumedAction = true;
4151
this.activity.runOnUiThread(
4252
this.activity::forceBackPressed);
4353
}
@@ -47,6 +57,8 @@ public void cancel() {
4757
*/
4858
@JavascriptInterface
4959
public void openUrl(String url) {
60+
if (this.consumedAction) return;
61+
this.consumedAction = true;
5062
Log.d(TAG, "Received openUrl request: " + url);
5163
if (Uri.parse(url).getScheme().equals("https")) {
5264
IntentHelper.openUrl(this.activity, url);
@@ -82,19 +94,25 @@ public boolean canInstall() {
8294
*/
8395
@JavascriptInterface
8496
public void install(String moduleUrl, String installTitle,String checksum) {
85-
if (!this.canInstall()) {
97+
if (this.consumedAction || !this.canInstall()) {
8698
return;
8799
}
100+
this.consumedAction = true;
88101
Log.d(TAG, "Received install request: " +
89102
moduleUrl + " " + installTitle + " " + checksum);
90103
Uri uri = Uri.parse(moduleUrl);
91-
if (uri.getScheme().equals("https") && uri.getHost().endsWith(".androidacy.com")) {
92-
this.activity.backOnResume = true;
93-
IntentHelper.openInstaller(this.activity,
94-
moduleUrl, installTitle, null, checksum);
95-
} else {
96-
this.activity.forceBackPressed();
104+
if (!AndroidacyUtil.isAndroidacyLink(moduleUrl, uri)) {
105+
this.forceQuitRaw("Non Androidacy module link used on Androidacy");
106+
return;
97107
}
108+
if (checksum != null) checksum = checksum.trim();
109+
if (!Hashes.checkSumValid(checksum)) {
110+
this.forceQuitRaw("Androidacy didn't provided a valid checksum");
111+
return;
112+
}
113+
this.activity.backOnResume = true;
114+
IntentHelper.openInstaller(this.activity,
115+
moduleUrl, installTitle, null, checksum);
98116
}
99117

100118
/**
@@ -137,7 +155,25 @@ public long getModuleVersionCode(String moduleId) {
137155
*/
138156
@JavascriptInterface
139157
public void hideActionBar() {
140-
this.activity.hideActionBar();
158+
if (this.consumedAction) return;
159+
this.consumedAction = true;
160+
this.activity.runOnUiThread(() -> {
161+
this.activity.hideActionBar();
162+
this.consumedAction = false;
163+
});
164+
}
165+
166+
/**
167+
* Show action bar if not visible, the action bar is only visible by default on notes.
168+
*/
169+
@JavascriptInterface
170+
public void showActionBar() {
171+
if (this.consumedAction) return;
172+
this.consumedAction = true;
173+
this.activity.runOnUiThread(() -> {
174+
this.activity.showActionBar();
175+
this.consumedAction = false;
176+
});
141177
}
142178

143179
/**
@@ -147,8 +183,7 @@ public void hideActionBar() {
147183
public boolean isAndroidacyModule(String moduleId) {
148184
LocalModuleInfo localModuleInfo = ModuleManager.getINSTANCE().getModules().get(moduleId);
149185
return localModuleInfo != null && ("Androidacy".equals(localModuleInfo.author) ||
150-
(localModuleInfo.config != null &&
151-
localModuleInfo.config.startsWith("https://www.androidacy.com/")));
186+
AndroidacyUtil.isAndroidacyLink(localModuleInfo.config));
152187
}
153188

154189
/**
@@ -157,7 +192,8 @@ public boolean isAndroidacyModule(String moduleId) {
157192
*/
158193
@JavascriptInterface
159194
public String getAndroidacyModuleFile(String moduleId, String moduleFile) {
160-
if (moduleFile == null || !this.isAndroidacyModule(moduleId)) return "";
195+
if (moduleFile == null || this.consumedAction ||
196+
!this.isAndroidacyModule(moduleId)) return "";
161197
File moduleFolder = new File("/data/adb/modules/" + moduleId);
162198
File absModuleFile = new File(moduleFolder, moduleFile).getAbsoluteFile();
163199
if (!absModuleFile.getPath().startsWith(moduleFolder.getPath())) return "";
@@ -175,7 +211,8 @@ public String getAndroidacyModuleFile(String moduleId, String moduleFile) {
175211
*/
176212
@JavascriptInterface
177213
public boolean setAndroidacyModuleMeta(String moduleId, String content) {
178-
if (content == null || !this.isAndroidacyModule(moduleId)) return false;
214+
if (content == null || this.consumedAction ||
215+
!this.isAndroidacyModule(moduleId)) return false;
179216
File androidacyMetaFile = new File(
180217
"/data/adb/modules/" + moduleId + "/.androidacy");
181218
try {

app/src/main/java/com/fox2code/mmm/compat/CompatActivity.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,23 @@ public void hideActionBar() {
164164
}
165165
}
166166

167+
public void showActionBar() {
168+
androidx.appcompat.app.ActionBar compatActionBar;
169+
try {
170+
compatActionBar = this.getSupportActionBar();
171+
} catch (Exception e) {
172+
Log.e(TAG, "Failed to call getSupportActionBar", e);
173+
compatActionBar = null; // Allow fallback to builtin actionBar.
174+
}
175+
if (compatActionBar != null) {
176+
compatActionBar.show();
177+
} else {
178+
android.app.ActionBar actionBar = this.getActionBar();
179+
if (actionBar != null)
180+
actionBar.show();
181+
}
182+
}
183+
167184
@Dimension @Px
168185
public int getActionBarHeight() {
169186
androidx.appcompat.app.ActionBar compatActionBar;

app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ protected void onCreate(Bundle savedInstanceState) {
132132
this.progressIndicator.setProgressCompat(progress, true);
133133
});
134134
});
135+
this.runOnUiThread(() -> {
136+
this.progressIndicator.setVisibility(View.GONE);
137+
this.progressIndicator.setIndeterminate(true);
138+
});
135139
if (this.canceled) return;
136140
if (checksum != null && !checksum.isEmpty()) {
137141
Log.d(TAG, "Checking for checksum: " + checksum);
@@ -178,8 +182,6 @@ protected void onCreate(Bundle savedInstanceState) {
178182
errMessage = "Failed to patch module zip";
179183
this.runOnUiThread(() -> {
180184
this.installerTerminal.addLine("- Patching " + name);
181-
this.progressIndicator.setVisibility(View.GONE);
182-
this.progressIndicator.setIndeterminate(true);
183185
});
184186
Log.i(TAG, "Patching: " + moduleCache.getName());
185187
try (OutputStream outputStream = new FileOutputStream(moduleCache)) {

app/src/main/java/com/fox2code/mmm/installer/InstallerInitializer.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ public static void tryGetMagiskPathAsync(Callback callback) {
4242
}
4343

4444
public static void tryGetMagiskPathAsync(Callback callback,boolean forceCheck) {
45-
String MAGISK_PATH = InstallerInitializer.MAGISK_PATH;
46-
if (MAGISK_PATH != null && !forceCheck) {
47-
callback.onPathReceived(MAGISK_PATH);
48-
return;
49-
}
45+
final String MAGISK_PATH = InstallerInitializer.MAGISK_PATH;
5046
Thread thread = new Thread("Magisk GetPath Thread") {
5147
@Override
5248
public void run() {
49+
if (MAGISK_PATH != null && !forceCheck) {
50+
callback.onPathReceived(MAGISK_PATH);
51+
return;
52+
}
5353
int error;
5454
String MAGISK_PATH = null;
5555
try {

app/src/main/java/com/fox2code/mmm/utils/Hashes.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,25 @@ public static boolean checkSumMatch(byte[] data, String checksum) {
8484
Log.d(TAG, "Checksum result (data: " + hash+ ",expected: " + checksum + ")");
8585
return hash.equals(checksum.toLowerCase(Locale.ROOT));
8686
}
87+
88+
public static boolean checkSumValid(String checksum) {
89+
if (checksum == null) return false;
90+
switch (checksum.length()) {
91+
case 0:
92+
default:
93+
return false;
94+
case 32:
95+
case 40:
96+
case 64:
97+
case 128:
98+
final int len = checksum.length();
99+
for (int i = 0; i < len; i++) {
100+
char c = checksum.charAt(i);
101+
if (c < '0' || c > 'f') return false;
102+
if (c > '9' && // Easier working with bits
103+
(c & 0b01011111) < 'A') return false;
104+
}
105+
return true;
106+
}
107+
}
87108
}

0 commit comments

Comments
 (0)