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

Commit ff1cb4f

Browse files
Updates
Signed-off-by: androidacy-user <opensource@androidacy.com>
1 parent 35b00cf commit ff1cb4f

File tree

7 files changed

+246
-219
lines changed

7 files changed

+246
-219
lines changed

app/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@ configurations {
154154
}
155155

156156
dependencies {
157+
// Big scary fingerprinting library
158+
// Actually, just used to generate device ID for androidacy (they use it for fraud detection)
159+
implementation "com.fingerprint.android:pro:2.2.1"
160+
implementation "com.github.fingerprintjs:fingerprint-android:2.0.0"
161+
162+
// If you use Java for you project, add also this line
163+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
164+
157165
// UI
158166
implementation 'androidx.appcompat:appcompat:1.5.1'
159167
implementation 'androidx.emoji2:emoji2:1.2.0'

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,12 @@ public androidx.work.Configuration getWorkManagerConfiguration() {
241241
private class Prism4jSwitchTheme implements Prism4jTheme {
242242
private final Prism4jTheme light = new Prism4jThemeDefault(Color.TRANSPARENT);
243243
private final Prism4jTheme dark = new Prism4jThemeDarkula(Color.TRANSPARENT);
244+
// Black theme
245+
private final Prism4jTheme black = new Prism4jThemeDefault(Color.BLACK);
244246

245247
private Prism4jTheme getTheme() {
246-
return isLightTheme() ? this.light : this.dark;
248+
// isLightTheme() means light, isDarkTheme() means dark, and isBlackTheme() means black
249+
return isLightTheme() ? light : isDarkTheme() ? dark : black;
247250
}
248251

249252
@Override
@@ -333,6 +336,11 @@ public boolean isLightTheme() {
333336
}
334337
}
335338

339+
@SuppressLint("NonConstantResourceId")
340+
public boolean isDarkTheme() {
341+
return !this.isLightTheme();
342+
}
343+
336344
@Override
337345
public void onCreate() {
338346
if (INSTANCE == null) INSTANCE = this;

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

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
package com.fox2code.mmm.androidacy;
22

3-
import android.annotation.SuppressLint;
3+
import android.content.Context;
44
import android.content.SharedPreferences;
5+
import android.os.Looper;
56
import android.util.Log;
67
import android.widget.Toast;
78

89
import androidx.annotation.NonNull;
910

11+
import com.fingerprintjs.android.fingerprint.Fingerprinter;
12+
import com.fingerprintjs.android.fingerprint.FingerprinterFactory;
13+
import com.fingerprintjs.android.fpjs_pro.Configuration;
14+
import com.fingerprintjs.android.fpjs_pro.FingerprintJS;
15+
import com.fingerprintjs.android.fpjs_pro.FingerprintJSFactory;
1016
import com.fox2code.mmm.BuildConfig;
1117
import com.fox2code.mmm.MainApplication;
1218
import com.fox2code.mmm.R;
@@ -17,6 +23,7 @@
1723
import com.fox2code.mmm.utils.Http;
1824
import com.fox2code.mmm.utils.HttpException;
1925
import com.fox2code.mmm.utils.PropUtils;
26+
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
2027

2128
import org.json.JSONArray;
2229
import org.json.JSONException;
@@ -84,44 +91,31 @@ public static String generateDeviceId() {
8491
if (deviceIdPref != null) {
8592
return deviceIdPref;
8693
} else {
87-
// Collect device information
88-
String device = android.os.Build.DEVICE;
89-
String model = android.os.Build.MODEL;
90-
String product = android.os.Build.PRODUCT;
91-
String manufacturer = android.os.Build.MANUFACTURER;
92-
String brand = android.os.Build.BRAND;
93-
String androidVersion = android.os.Build.VERSION.RELEASE;
94-
String androidSdk = String.valueOf(android.os.Build.VERSION.SDK_INT);
95-
@SuppressLint("HardwareIds") String androidId = android.provider.Settings.Secure.getString(MainApplication.getINSTANCE().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
96-
// Generate a unique ID for this device. For privacy reasons, we don't want to send this
97-
// info directly to the server, so we hash it.
98-
String deviceId = androidId + device + model + product + manufacturer + brand + androidVersion + androidSdk;
99-
// Now, we need to hash the device ID. We use SHA-256, which is a secure hash function.
100-
// This means that it's impossible to reverse the hash and get the original device ID.
101-
// We use the SHA-256 hash because it's the same hash function used by the API to hash
102-
// the device ID.
103-
try {
104-
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
105-
byte[] hash = digest.digest(deviceId.getBytes(java.nio.charset.StandardCharsets.UTF_8));
106-
// Convert the hash to a normal string
107-
StringBuilder hexString = new StringBuilder();
108-
for (byte b : hash) {
109-
String hex = Integer.toHexString(0xff & b);
110-
if (hex.length() == 1) {
111-
hexString.append('0');
112-
}
113-
hexString.append(hex);
114-
}
115-
// Save the device ID to the shared preferences
94+
Context context = MainApplication.getINSTANCE().getApplicationContext();
95+
FingerprintJSFactory factory = new FingerprintJSFactory(context);
96+
Configuration.Region region = Configuration.Region.US;
97+
Configuration configuration = new Configuration(
98+
"NiZiHi266YaTLreOIOzc",
99+
region,
100+
region.getEndpointUrl(),
101+
true
102+
);
103+
104+
FingerprintJS fpjsClient = factory.createInstance(
105+
configuration
106+
);
107+
108+
fpjsClient.getVisitorId(visitorIdResponse -> {
109+
// Use the ID
110+
String visitorId = visitorIdResponse.getVisitorId();
111+
// Save the ID in the shared preferences
116112
SharedPreferences.Editor editor = sharedPreferences.edit();
117-
editor.putString("device_id", hexString.toString());
113+
editor.putString("device_id", visitorId);
118114
editor.apply();
119-
return hexString.toString();
120-
} catch (java.security.NoSuchAlgorithmException e) {
121-
// This should never happen, but if it does, we'll just return the device ID without
122-
// hashing it.
123-
return deviceId;
124-
}
115+
return null;
116+
});
117+
// return the id
118+
return sharedPreferences.getString("device_id", null);
125119
}
126120
}
127121

@@ -147,17 +141,37 @@ public boolean isValidToken(String token) throws IOException {
147141
@Override
148142
protected boolean prepare() {
149143
if (Http.needCaptchaAndroidacy()) return false;
144+
// Check if we have a device ID yet
145+
SharedPreferences sharedPreferences = MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0);
146+
String deviceIdPref = sharedPreferences.getString("device_id", null);
147+
if (deviceIdPref == null) {
148+
// Generate a device ID
149+
generateDeviceId();
150+
// Loop until we have a device ID
151+
while (sharedPreferences.getString("device_id", null) == null) {
152+
try {
153+
Thread.sleep(100);
154+
} catch (InterruptedException e) {
155+
e.printStackTrace();
156+
}
157+
}
158+
}
150159
// Implementation details discussed on telegram
151160
// First, ping the server to check if it's alive
152161
try {
153162
Http.doHttpGet("https://" + this.host + "/ping", false);
154163
} catch (Exception e) {
155164
Log.e(TAG, "Failed to ping server", e);
156165
// Inform user
157-
/*if (!HttpException.shouldTimeout(e)) {
158-
UiThreadHandler.run(() -> Toast.makeText(MainApplication.getINSTANCE(),
159-
R.string.androidacy_server_down, Toast.LENGTH_SHORT).show());
160-
}*/
166+
Looper.prepare();
167+
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(MainApplication.getINSTANCE().getBaseContext());
168+
builder.setTitle("Androidacy Server Down");
169+
builder.setMessage("The Androidacy server is down. Unfortunately, this means that you" +
170+
" will not be able to download or view modules from the Androidacy repository" +
171+
". Please try again later.");
172+
builder.setPositiveButton("OK", (dialog, which) -> dialog.dismiss());
173+
builder.show();
174+
Looper.loop();
161175
return false;
162176
}
163177
String deviceId = generateDeviceId();
@@ -383,10 +397,6 @@ public String getName() {
383397
return this.testMode ? super.getName() + " (Test Mode)" : super.getName();
384398
}
385399

386-
String getToken() {
387-
return this.token;
388-
}
389-
390400
public void setToken(String token) {
391401
if (Http.hasWebView()) {
392402
this.token = token;

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -542,17 +542,22 @@ public void onCreatePreferencesAndroidacy() {
542542
return true;
543543
});
544544
}
545-
String[] originalApiKeyRef = new String[]{
546-
MainApplication.getSharedPreferences().getString("pref_androidacy_api_token", "")};
547-
// Create the pref_androidacy_repo_api_key text input with validation
548-
EditTextPreference prefAndroidacyRepoApiKey = findPreference("pref_androidacy_api_token");
549-
assert prefAndroidacyRepoApiKey != null;
545+
String[] originalApiKeyRef = new String[]{MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).getString("pref_androidacy_api_token", null)};
546+
// Get the dummy pref_androidacy_repo_api_token EditTextPreference
547+
EditTextPreference prefAndroidacyRepoApiKey = Objects.requireNonNull(findPreference("pref_androidacy_api_token"));
548+
prefAndroidacyRepoApiKey.setDependency("pref_androidacy_repo_enabled");
549+
prefAndroidacyRepoApiKey.setTitle(R.string.api_key);
550+
prefAndroidacyRepoApiKey.setSummary(R.string.api_key_summary);
551+
prefAndroidacyRepoApiKey.setDialogTitle(R.string.api_key);
552+
prefAndroidacyRepoApiKey.setDefaultValue(originalApiKeyRef[0]);
553+
// Set the value to the current value
554+
prefAndroidacyRepoApiKey.setText(originalApiKeyRef[0]);
550555
prefAndroidacyRepoApiKey.setOnBindEditTextListener(editText -> {
551556
editText.setSingleLine();
552557
// Make the single line wrap
553558
editText.setHorizontallyScrolling(false);
554-
// Set the height to the height of 2 lines
555-
editText.setHeight(editText.getLineHeight() * 3);
559+
// Set the height to the maximum required to fit the text
560+
editText.setMaxLines(Integer.MAX_VALUE);
556561
// Make ok button say "Save"
557562
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
558563
});
@@ -573,8 +578,7 @@ public void onCreatePreferencesAndroidacy() {
573578
new Thread(() -> {
574579
// If key is empty, just remove it and change the text of the snack bar
575580
if (apiKey.isEmpty()) {
576-
MainApplication.getSharedPreferences().edit().remove(
577-
"pref_androidacy_api_token").apply();
581+
MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().remove("pref_androidacy_api_token").apply();
578582
new Handler(Looper.getMainLooper()).post(() -> {
579583
Snackbar.make(requireView(), R.string.api_key_removed, Snackbar.LENGTH_SHORT).show();
580584
// Show dialog to restart app with ok button
@@ -610,8 +614,7 @@ public void onCreatePreferencesAndroidacy() {
610614
new Handler(Looper.getMainLooper()).post(() -> {
611615
Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show();
612616
// Save the original key
613-
MainApplication.getSharedPreferences().edit().putString(
614-
"pref_androidacy_api_token", originalApiKeyRef[0]).apply();
617+
MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().putString("pref_androidacy_api_token", originalApiKeyRef[0]).apply();
615618
// Re-show the dialog with an error
616619
prefAndroidacyRepoApiKey.performClick();
617620
// Show error
@@ -631,8 +634,7 @@ public void onCreatePreferencesAndroidacy() {
631634
if (valid) {
632635
originalApiKeyRef[0] = apiKey;
633636
RepoManager.getINSTANCE().getAndroidacyRepoData().setToken(apiKey);
634-
MainApplication.getSharedPreferences().edit().putString(
635-
"pref_androidacy_api_token", apiKey).apply();
637+
MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().putString("pref_androidacy_api_token", apiKey).apply();
636638
// Snackbar with success and restart button
637639
new Handler(Looper.getMainLooper()).post(() -> {
638640
Snackbar.make(requireView(), R.string.api_key_valid, Snackbar.LENGTH_SHORT).show();
@@ -667,7 +669,7 @@ public void onCreatePreferencesAndroidacy() {
667669
new Handler(Looper.getMainLooper()).post(() -> {
668670
Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show();
669671
// Save the original key
670-
MainApplication.getSharedPreferences().edit().putString(
672+
MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().putString(
671673
"pref_androidacy_api_token", originalApiKeyRef[0]).apply();
672674
// Re-show the dialog with an error
673675
prefAndroidacyRepoApiKey.performClick();
@@ -680,6 +682,8 @@ public void onCreatePreferencesAndroidacy() {
680682
}).start();
681683
return true;
682684
});
685+
// make sure the preference is visible if repo is enabled
686+
prefAndroidacyRepoApiKey.setVisible(RepoManager.getINSTANCE().getAndroidacyRepoData().isEnabled());
683687
}
684688

685689
@SuppressLint("RestrictedApi")

0 commit comments

Comments
 (0)