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

Commit 78a72ba

Browse files
committed
Re-implement Androidacy captcha error handler
1 parent 8b3d26a commit 78a72ba

File tree

10 files changed

+194
-88
lines changed

10 files changed

+194
-88
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ public void commonNext() {
211211
(int) (value * PRECISION), true) :() ->
212212
progressIndicator.setProgressCompat(
213213
(int) (value * PRECISION * 0.75F), true)));
214+
NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder);
214215
if (!NotificationType.NO_INTERNET.shouldRemove()) {
215216
moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET);
216217
} else {
@@ -372,6 +373,7 @@ public void commonNext() {
372373
NoodleDebug noodleDebug = NoodleDebug.getNoodleDebug();
373374
if (MainApplication.isShowcaseMode())
374375
moduleViewListBuilder.addNotification(NotificationType.SHOWCASE_MODE);
376+
NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder);
375377
if (!NotificationType.NO_INTERNET.shouldRemove())
376378
moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET);
377379
else if (AppUpdateManager.getAppUpdateManager().checkUpdate(false))
@@ -433,6 +435,7 @@ public void onRefresh() {
433435
(int) (value * PRECISION), true) :() ->
434436
progressIndicator.setProgressCompat(
435437
(int) (value * PRECISION * 0.75F), true)));
438+
NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder);
436439
if (!NotificationType.NO_INTERNET.shouldRemove()) {
437440
moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET);
438441
} else {
@@ -470,6 +473,7 @@ public void onRefresh() {
470473
this.progressIndicator.setVisibility(View.GONE);
471474
this.swipeRefreshLayout.setRefreshing(false);
472475
});
476+
NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder);
473477
if (!NotificationType.NO_INTERNET.shouldRemove()) {
474478
this.moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET);
475479
}

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,6 @@ public static String formatTime(long timeStamp) {
204204
private FoxThemeWrapper markwonThemeContext;
205205
private Markwon markwon;
206206

207-
public static MainApplication getInstance() {
208-
return INSTANCE;
209-
}
210-
211207
public Markwon getMarkwon() {
212208
if (this.markwon != null)
213209
return this.markwon;

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import com.fox2code.foxcompat.FoxActivity;
1212
import com.fox2code.mmm.installer.InstallerInitializer;
13+
import com.fox2code.mmm.module.ModuleViewListBuilder;
1314
import com.fox2code.mmm.repo.RepoManager;
1415
import com.fox2code.mmm.utils.Files;
1516
import com.fox2code.mmm.utils.Http;
@@ -69,6 +70,15 @@ public boolean shouldRemove() {
6970
RepoManager.getINSTANCE().hasConnectivity();
7071
}
7172
},
73+
NEED_CAPTCHA_ANDROIDACY(R.string.androidacy_need_captcha, R.drawable.ic_baseline_refresh_24, v ->
74+
IntentHelper.openUrlAndroidacy(v.getContext(),
75+
"https://" + Http.needCaptchaAndroidacyHost() + "/", false)) {
76+
@Override
77+
public boolean shouldRemove() {
78+
return !RepoManager.isAndroidacyRepoEnabled()
79+
|| !Http.needCaptchaAndroidacy();
80+
}
81+
},
7282
NO_WEB_VIEW(R.string.no_web_view, R.drawable.ic_baseline_android_24) {
7383
@Override
7484
public boolean shouldRemove() {
@@ -181,4 +191,8 @@ private static boolean needPatch(File target) throws IOException {
181191
public boolean shouldRemove() {
182192
return false;
183193
}
194+
195+
public final void autoAdd(ModuleViewListBuilder moduleViewListBuilder) {
196+
if (!shouldRemove()) moduleViewListBuilder.addNotification(this);
197+
}
184198
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
9191
this.forceBackPressed();
9292
return;
9393
}
94+
Http.markCaptchaAndroidacySolved();
9495
if (!url.contains(AndroidacyUtil.REFERRER)) {
9596
if (url.lastIndexOf('/') < url.lastIndexOf('?')) {
9697
url = url + '&' + AndroidacyUtil.REFERRER;

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

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.content.SharedPreferences;
44
import android.util.Log;
5-
import android.webkit.CookieManager;
65
import android.widget.Toast;
76

87
import androidx.annotation.NonNull;
@@ -14,13 +13,16 @@
1413
import com.fox2code.mmm.repo.RepoManager;
1514
import com.fox2code.mmm.repo.RepoModule;
1615
import com.fox2code.mmm.utils.Http;
16+
import com.fox2code.mmm.utils.HttpException;
1717
import com.fox2code.mmm.utils.PropUtils;
18+
import com.topjohnwu.superuser.internal.UiThreadHandler;
1819

1920
import org.json.JSONArray;
2021
import org.json.JSONException;
2122
import org.json.JSONObject;
2223

2324
import java.io.File;
25+
import java.io.IOException;
2426
import java.nio.charset.StandardCharsets;
2527
import java.util.ArrayList;
2628
import java.util.Iterator;
@@ -73,49 +75,58 @@ private static String filterURL(String url) {
7375
return url;
7476
}
7577

76-
public <string> boolean isValidToken(string token) {
78+
public boolean isValidToken(String token) throws IOException {
7779
try {
7880
Http.doHttpGet("https://" + this.host + "/auth/me?token=" + token, false);
79-
} catch (Exception e) {
80-
if ("Received error code: 419".equals(e.getMessage()) || "Received error code: 429".equals(e.getMessage())) {
81-
Log.e(TAG, "We are being rate limited!", e);
82-
long time = System.currentTimeMillis();
83-
this.androidacyBlockade = time + 3_600_000L;
81+
} catch (HttpException e) {
82+
if (e.getErrorCode() == 401) {
83+
Log.w(TAG, "Invalid token, resetting...");
84+
// Remove saved preference
85+
SharedPreferences.Editor editor = this.cachedPreferences.edit();
86+
editor.remove("androidacy_api_token");
87+
editor.apply();
8488
return false;
8589
}
86-
Log.w(TAG, "Invalid token, resetting...");
87-
// Remove saved preference
88-
SharedPreferences.Editor editor = this.cachedPreferences.edit();
89-
editor.remove("androidacy_api_token");
90-
editor.apply();
91-
return false;
90+
throw e;
9291
}
9392
// If status code is 200, we are good
9493
return true;
9594
}
9695

9796
@Override
9897
protected boolean prepare() {
98+
if (Http.needCaptchaAndroidacy()) return false;
9999
// Implementation details discussed on telegram
100100
// First, ping the server to check if it's alive
101101
try {
102102
Http.doHttpGet("https://" + this.host + "/ping", false);
103103
} catch (Exception e) {
104104
Log.e(TAG, "Failed to ping server", e);
105105
// Inform user
106-
new Thread(() -> Toast.makeText(MainApplication.getINSTANCE(), R.string.androidacy_server_down, Toast.LENGTH_LONG).show()).start();
106+
if (!HttpException.shouldTimeout(e)) {
107+
UiThreadHandler.run(() -> Toast.makeText(MainApplication.getINSTANCE(),
108+
R.string.androidacy_server_down, Toast.LENGTH_SHORT).show());
109+
}
107110
return false;
108111
}
109112
long time = System.currentTimeMillis();
110113
if (this.androidacyBlockade > time) return false;
111114
this.androidacyBlockade = time + 30_000L;
112-
if (this.token == null) {
113-
this.token = this.cachedPreferences.getString("pref_androidacy_api_token", null);
114-
if (this.token != null && !this.isValidToken(this.token)) {
115+
try {
116+
if (this.token == null) {
117+
this.token = this.cachedPreferences.getString("pref_androidacy_api_token", null);
118+
if (this.token != null && !this.isValidToken(this.token)) {
119+
this.token = null;
120+
}
121+
} else if (!this.isValidToken(this.token)) {
115122
this.token = null;
116123
}
117-
} else if (!this.isValidToken(this.token)) {
118-
this.token = null;
124+
} catch (IOException e) {
125+
if (HttpException.shouldTimeout(e)) {
126+
Log.e(TAG, "We are being rate limited!", e);
127+
this.androidacyBlockade = time + 3_600_000L;
128+
}
129+
return false;
119130
}
120131
if (token == null) {
121132
try {
@@ -142,7 +153,7 @@ protected boolean prepare() {
142153
// Save token to shared preference
143154
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_api_token", token).apply();
144155
} catch (Exception e) {
145-
if ("Received error code: 419".equals(e.getMessage()) || "Received error code: 429".equals(e.getMessage()) || "Received error code: 503".equals(e.getMessage())) {
156+
if (HttpException.shouldTimeout(e)) {
146157
Log.e(TAG, "We are being rate limited!", e);
147158
this.androidacyBlockade = time + 3_600_000L;
148159
}
@@ -308,10 +319,8 @@ String getToken() {
308319
return this.token;
309320
}
310321

311-
void setToken(String token) {
322+
public void setToken(String token) {
312323
if (Http.hasWebView()) {
313-
// TODO: Figure out why this is needed
314-
CookieManager.getInstance().setCookie("https://.androidacy.com/", "USER=" + token + "; expires=Fri, 31 Dec 9999 23:59:59 GMT;" + " path=/; secure; domain=.androidacy.com");
315324
this.token = token;
316325
}
317326
}

app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ public void onCreatePreferencesAndroidacy() {
462462
return true;
463463
});
464464
}
465-
String originalApiKey = MainApplication.getSharedPreferences().getString("pref_androidacy_api_token", "");
465+
String[] originalApiKeyRef = new String[]{
466+
MainApplication.getSharedPreferences().getString("pref_androidacy_api_token", "")};
466467
// Create the pref_androidacy_repo_api_key text input with validation
467468
EditTextPreference prefAndroidacyRepoApiKey = findPreference("pref_androidacy_repo_api_key");
468469
assert prefAndroidacyRepoApiKey != null;
@@ -477,44 +478,57 @@ public void onCreatePreferencesAndroidacy() {
477478
});
478479
prefAndroidacyRepoApiKey.setPositiveButtonText(R.string.save_api_key);
479480
prefAndroidacyRepoApiKey.setOnPreferenceChangeListener((preference, newValue) -> {
481+
if (originalApiKeyRef[0].equals(newValue)) return true; // Skip if nothing changed.
480482
// Curious if this actually works - so crash the app on purpose
481483
// throw new RuntimeException("This is a test crash");
482484
// get original api key
483485
String apiKey = String.valueOf(newValue);
484486
// Show snack bar with indeterminate progress
485-
Snackbar.make(requireView(), R.string.checking_api_key, Snackbar.LENGTH_INDEFINITE).setAction(R.string.cancel, v -> {
487+
Snackbar.make(requireView(), R.string.checking_api_key, Snackbar.LENGTH_INDEFINITE)
488+
.setAction(R.string.cancel, v -> {
486489
// Restore the original api key
487-
prefAndroidacyRepoApiKey.setText(originalApiKey);
490+
prefAndroidacyRepoApiKey.setText(originalApiKeyRef[0]);
488491
}).show();
489492
// Check the API key on a background thread
490493
new Thread(() -> {
491494
// If key is empty, just remove it and change the text of the snack bar
492495
if (apiKey.isEmpty()) {
493-
MainApplication.getSharedPreferences().edit().remove("pref_androidacy_repo_api_key").apply();
494-
new Handler(Looper.getMainLooper()).post(() -> Snackbar.make(requireView(), R.string.api_key_removed, Snackbar.LENGTH_SHORT).show());
496+
MainApplication.getSharedPreferences().edit().remove(
497+
"pref_androidacy_repo_api_key").apply();
498+
new Handler(Looper.getMainLooper()).post(() -> Snackbar.make(requireView(),
499+
R.string.api_key_removed, Snackbar.LENGTH_SHORT).show());
495500
} else {
496501
// If key < 64 chars, it's not valid
497502
if (apiKey.length() < 64) {
498503
new Handler(Looper.getMainLooper()).post(() -> {
499504
Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show();
500505
// Save the original key
501-
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_api_token", originalApiKey).apply();
506+
MainApplication.getSharedPreferences().edit().putString(
507+
"pref_androidacy_api_token", originalApiKeyRef[0]).apply();
502508
// Re-show the dialog with an error
503509
prefAndroidacyRepoApiKey.performClick();
504510
// Show error
505511
prefAndroidacyRepoApiKey.setDialogMessage(getString(R.string.api_key_invalid));
506512
});
507513
} else {
508-
boolean valid = AndroidacyRepoData.getInstance().isValidToken(apiKey);
514+
boolean valid = false;
515+
try {
516+
valid = AndroidacyRepoData.getInstance().isValidToken(apiKey);
517+
} catch (IOException ignored) {}
509518
// If the key is valid, save it
510519
if (valid) {
511-
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_repo_api_key", apiKey).apply();
512-
new Handler(Looper.getMainLooper()).post(() -> Snackbar.make(requireView(), R.string.api_key_valid, Snackbar.LENGTH_SHORT).show());
520+
originalApiKeyRef[0] = apiKey;
521+
RepoManager.getINSTANCE().getAndroidacyRepoData().setToken(apiKey);
522+
MainApplication.getSharedPreferences().edit().putString(
523+
"pref_androidacy_repo_api_key", apiKey).apply();
524+
new Handler(Looper.getMainLooper()).post(() -> Snackbar.make(requireView(),
525+
R.string.api_key_valid, Snackbar.LENGTH_SHORT).show());
513526
} else {
514527
new Handler(Looper.getMainLooper()).post(() -> {
515528
Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show();
516529
// Save the original key
517-
MainApplication.getSharedPreferences().edit().putString("pref_androidacy_api_token", originalApiKey).apply();
530+
MainApplication.getSharedPreferences().edit().putString(
531+
"pref_androidacy_api_token", originalApiKeyRef[0]).apply();
518532
// Re-show the dialog with an error
519533
prefAndroidacyRepoApiKey.performClick();
520534
// Show error

0 commit comments

Comments
 (0)