From ff1cb4fbb667fdba74ae4fafdbe21ccd458a68ac Mon Sep 17 00:00:00 2001 From: androidacy-user Date: Fri, 2 Dec 2022 11:16:42 -0500 Subject: [PATCH] Updates Signed-off-by: androidacy-user --- app/build.gradle | 8 + .../com/fox2code/mmm/MainApplication.java | 10 +- .../mmm/androidacy/AndroidacyRepoData.java | 100 +++--- .../mmm/settings/SettingsActivity.java | 32 +- app/src/main/res/xml/repo_preferences.xml | 311 +++++++++--------- build.gradle | 3 + settings.gradle | 1 + 7 files changed, 246 insertions(+), 219 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index da2dc7e..b694d78 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -154,6 +154,14 @@ configurations { } dependencies { + // Big scary fingerprinting library + // Actually, just used to generate device ID for androidacy (they use it for fraud detection) + implementation "com.fingerprint.android:pro:2.2.1" + implementation "com.github.fingerprintjs:fingerprint-android:2.0.0" + + // If you use Java for you project, add also this line + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + // UI implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'androidx.emoji2:emoji2:1.2.0' diff --git a/app/src/main/java/com/fox2code/mmm/MainApplication.java b/app/src/main/java/com/fox2code/mmm/MainApplication.java index 5fbfea7..1a9abd9 100644 --- a/app/src/main/java/com/fox2code/mmm/MainApplication.java +++ b/app/src/main/java/com/fox2code/mmm/MainApplication.java @@ -241,9 +241,12 @@ public class MainApplication extends FoxApplication private class Prism4jSwitchTheme implements Prism4jTheme { private final Prism4jTheme light = new Prism4jThemeDefault(Color.TRANSPARENT); private final Prism4jTheme dark = new Prism4jThemeDarkula(Color.TRANSPARENT); + // Black theme + private final Prism4jTheme black = new Prism4jThemeDefault(Color.BLACK); private Prism4jTheme getTheme() { - return isLightTheme() ? this.light : this.dark; + // isLightTheme() means light, isDarkTheme() means dark, and isBlackTheme() means black + return isLightTheme() ? light : isDarkTheme() ? dark : black; } @Override @@ -333,6 +336,11 @@ public class MainApplication extends FoxApplication } } + @SuppressLint("NonConstantResourceId") + public boolean isDarkTheme() { + return !this.isLightTheme(); + } + @Override public void onCreate() { if (INSTANCE == null) INSTANCE = this; diff --git a/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java b/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java index 3c9b6e7..3c706dc 100644 --- a/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java +++ b/app/src/main/java/com/fox2code/mmm/androidacy/AndroidacyRepoData.java @@ -1,12 +1,18 @@ package com.fox2code.mmm.androidacy; -import android.annotation.SuppressLint; +import android.content.Context; import android.content.SharedPreferences; +import android.os.Looper; import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; +import com.fingerprintjs.android.fingerprint.Fingerprinter; +import com.fingerprintjs.android.fingerprint.FingerprinterFactory; +import com.fingerprintjs.android.fpjs_pro.Configuration; +import com.fingerprintjs.android.fpjs_pro.FingerprintJS; +import com.fingerprintjs.android.fpjs_pro.FingerprintJSFactory; import com.fox2code.mmm.BuildConfig; import com.fox2code.mmm.MainApplication; import com.fox2code.mmm.R; @@ -17,6 +23,7 @@ import com.fox2code.mmm.repo.RepoModule; import com.fox2code.mmm.utils.Http; import com.fox2code.mmm.utils.HttpException; import com.fox2code.mmm.utils.PropUtils; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.json.JSONArray; import org.json.JSONException; @@ -84,44 +91,31 @@ public final class AndroidacyRepoData extends RepoData { if (deviceIdPref != null) { return deviceIdPref; } else { - // Collect device information - String device = android.os.Build.DEVICE; - String model = android.os.Build.MODEL; - String product = android.os.Build.PRODUCT; - String manufacturer = android.os.Build.MANUFACTURER; - String brand = android.os.Build.BRAND; - String androidVersion = android.os.Build.VERSION.RELEASE; - String androidSdk = String.valueOf(android.os.Build.VERSION.SDK_INT); - @SuppressLint("HardwareIds") String androidId = android.provider.Settings.Secure.getString(MainApplication.getINSTANCE().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); - // Generate a unique ID for this device. For privacy reasons, we don't want to send this - // info directly to the server, so we hash it. - String deviceId = androidId + device + model + product + manufacturer + brand + androidVersion + androidSdk; - // Now, we need to hash the device ID. We use SHA-256, which is a secure hash function. - // This means that it's impossible to reverse the hash and get the original device ID. - // We use the SHA-256 hash because it's the same hash function used by the API to hash - // the device ID. - try { - java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(deviceId.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - // Convert the hash to a normal string - StringBuilder hexString = new StringBuilder(); - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - // Save the device ID to the shared preferences + Context context = MainApplication.getINSTANCE().getApplicationContext(); + FingerprintJSFactory factory = new FingerprintJSFactory(context); + Configuration.Region region = Configuration.Region.US; + Configuration configuration = new Configuration( + "NiZiHi266YaTLreOIOzc", + region, + region.getEndpointUrl(), + true + ); + + FingerprintJS fpjsClient = factory.createInstance( + configuration + ); + + fpjsClient.getVisitorId(visitorIdResponse -> { + // Use the ID + String visitorId = visitorIdResponse.getVisitorId(); + // Save the ID in the shared preferences SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString("device_id", hexString.toString()); + editor.putString("device_id", visitorId); editor.apply(); - return hexString.toString(); - } catch (java.security.NoSuchAlgorithmException e) { - // This should never happen, but if it does, we'll just return the device ID without - // hashing it. - return deviceId; - } + return null; + }); + // return the id + return sharedPreferences.getString("device_id", null); } } @@ -147,6 +141,21 @@ public final class AndroidacyRepoData extends RepoData { @Override protected boolean prepare() { if (Http.needCaptchaAndroidacy()) return false; + // Check if we have a device ID yet + SharedPreferences sharedPreferences = MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0); + String deviceIdPref = sharedPreferences.getString("device_id", null); + if (deviceIdPref == null) { + // Generate a device ID + generateDeviceId(); + // Loop until we have a device ID + while (sharedPreferences.getString("device_id", null) == null) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } // Implementation details discussed on telegram // First, ping the server to check if it's alive try { @@ -154,10 +163,15 @@ public final class AndroidacyRepoData extends RepoData { } catch (Exception e) { Log.e(TAG, "Failed to ping server", e); // Inform user - /*if (!HttpException.shouldTimeout(e)) { - UiThreadHandler.run(() -> Toast.makeText(MainApplication.getINSTANCE(), - R.string.androidacy_server_down, Toast.LENGTH_SHORT).show()); - }*/ + 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(); @@ -383,10 +397,6 @@ public final class AndroidacyRepoData extends RepoData { return this.testMode ? super.getName() + " (Test Mode)" : super.getName(); } - String getToken() { - return this.token; - } - public void setToken(String token) { if (Http.hasWebView()) { this.token = token; diff --git a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java index ef0ee43..2a16e0b 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -542,17 +542,22 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { return true; }); } - String[] originalApiKeyRef = new String[]{ - MainApplication.getSharedPreferences().getString("pref_androidacy_api_token", "")}; - // Create the pref_androidacy_repo_api_key text input with validation - EditTextPreference prefAndroidacyRepoApiKey = findPreference("pref_androidacy_api_token"); - assert prefAndroidacyRepoApiKey != null; + String[] originalApiKeyRef = new String[]{MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).getString("pref_androidacy_api_token", null)}; + // Get the dummy pref_androidacy_repo_api_token EditTextPreference + EditTextPreference prefAndroidacyRepoApiKey = Objects.requireNonNull(findPreference("pref_androidacy_api_token")); + prefAndroidacyRepoApiKey.setDependency("pref_androidacy_repo_enabled"); + prefAndroidacyRepoApiKey.setTitle(R.string.api_key); + prefAndroidacyRepoApiKey.setSummary(R.string.api_key_summary); + prefAndroidacyRepoApiKey.setDialogTitle(R.string.api_key); + prefAndroidacyRepoApiKey.setDefaultValue(originalApiKeyRef[0]); + // Set the value to the current value + prefAndroidacyRepoApiKey.setText(originalApiKeyRef[0]); prefAndroidacyRepoApiKey.setOnBindEditTextListener(editText -> { editText.setSingleLine(); // Make the single line wrap editText.setHorizontallyScrolling(false); - // Set the height to the height of 2 lines - editText.setHeight(editText.getLineHeight() * 3); + // Set the height to the maximum required to fit the text + editText.setMaxLines(Integer.MAX_VALUE); // Make ok button say "Save" editText.setImeOptions(EditorInfo.IME_ACTION_DONE); }); @@ -573,8 +578,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { new Thread(() -> { // If key is empty, just remove it and change the text of the snack bar if (apiKey.isEmpty()) { - MainApplication.getSharedPreferences().edit().remove( - "pref_androidacy_api_token").apply(); + MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().remove("pref_androidacy_api_token").apply(); new Handler(Looper.getMainLooper()).post(() -> { Snackbar.make(requireView(), R.string.api_key_removed, Snackbar.LENGTH_SHORT).show(); // Show dialog to restart app with ok button @@ -610,8 +614,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { new Handler(Looper.getMainLooper()).post(() -> { Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show(); // Save the original key - MainApplication.getSharedPreferences().edit().putString( - "pref_androidacy_api_token", originalApiKeyRef[0]).apply(); + MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().putString("pref_androidacy_api_token", originalApiKeyRef[0]).apply(); // Re-show the dialog with an error prefAndroidacyRepoApiKey.performClick(); // Show error @@ -631,8 +634,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { if (valid) { originalApiKeyRef[0] = apiKey; RepoManager.getINSTANCE().getAndroidacyRepoData().setToken(apiKey); - MainApplication.getSharedPreferences().edit().putString( - "pref_androidacy_api_token", apiKey).apply(); + MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().putString("pref_androidacy_api_token", apiKey).apply(); // Snackbar with success and restart button new Handler(Looper.getMainLooper()).post(() -> { Snackbar.make(requireView(), R.string.api_key_valid, Snackbar.LENGTH_SHORT).show(); @@ -667,7 +669,7 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { new Handler(Looper.getMainLooper()).post(() -> { Snackbar.make(requireView(), R.string.api_key_invalid, Snackbar.LENGTH_SHORT).show(); // Save the original key - MainApplication.getSharedPreferences().edit().putString( + MainApplication.getINSTANCE().getSharedPreferences("androidacy", 0).edit().putString( "pref_androidacy_api_token", originalApiKeyRef[0]).apply(); // Re-show the dialog with an error prefAndroidacyRepoApiKey.performClick(); @@ -680,6 +682,8 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { }).start(); return true; }); + // make sure the preference is visible if repo is enabled + prefAndroidacyRepoApiKey.setVisible(RepoManager.getINSTANCE().getAndroidacyRepoData().isEnabled()); } @SuppressLint("RestrictedApi") diff --git a/app/src/main/res/xml/repo_preferences.xml b/app/src/main/res/xml/repo_preferences.xml index e48698a..eecfa44 100644 --- a/app/src/main/res/xml/repo_preferences.xml +++ b/app/src/main/res/xml/repo_preferences.xml @@ -1,310 +1,303 @@ - + + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_magisk_alt_repo_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_magisk_alt_repo_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_magisk_alt_repo_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_magisk_alt_repo_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> - + app:switchTextOn="@string/repo_enabled" /> + + app:key="pref_androidacy_api_token" + app:singleLineTitle="false" + app:isPreferenceVisible="false" + app:title="@string/api_key" /> + app:title="@string/androidacy_test_mode_pref" /> + app:key="pref_androidacy_repo_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_androidacy_repo_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_androidacy_repo_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_androidacy_repo_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:icon="@drawable/ic_baseline_info_24" + app:key="pref_androidacy_ads_disclaimer" + app:singleLineTitle="false" + app:summary="@string/androidacy_repo_info" /> + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_dg_magisk_repo_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_dg_magisk_repo_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_dg_magisk_repo_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_dg_magisk_repo_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_custom_repo_0_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_custom_repo_0_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_custom_repo_0_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_custom_repo_0_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:key="pref_custom_repo_0_delete" + app:singleLineTitle="false" + app:title="@string/remove_repo" /> + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_custom_repo_1_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_custom_repo_1_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_custom_repo_1_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_custom_repo_1_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:key="pref_custom_repo_1_delete" + app:singleLineTitle="false" + app:title="@string/remove_repo" /> + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_custom_repo_2_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_custom_repo_2_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_custom_repo_2_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_custom_repo_2_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:key="pref_custom_repo_2_delete" + app:singleLineTitle="false" + app:title="@string/remove_repo" /> + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_custom_repo_3_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_custom_repo_3_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_custom_repo_3_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_custom_repo_3_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:key="pref_custom_repo_3_delete" + app:singleLineTitle="false" + app:title="@string/remove_repo" /> + app:switchTextOn="@string/repo_enabled" /> + app:key="pref_custom_repo_4_website" + app:singleLineTitle="false" + app:title="@string/website" /> + app:key="pref_custom_repo_4_support" + app:singleLineTitle="false" + app:title="@string/support" /> + app:key="pref_custom_repo_4_donate" + app:singleLineTitle="false" + app:title="@string/donate" /> + app:key="pref_custom_repo_4_submit" + app:singleLineTitle="false" + app:title="@string/submit_modules" /> + app:key="pref_custom_repo_4_delete" + app:singleLineTitle="false" + app:title="@string/remove_repo" /> + app:key="pref_custom_add_repo_button" + app:singleLineTitle="false" + app:title="@string/add_repo" /> diff --git a/build.gradle b/build.gradle index 5d064ef..6a44e52 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,8 @@ buildscript { google() mavenCentral() gradlePluginPortal() + maven { url 'https://maven.fpregistry.io/releases' } + maven { url 'https://jitpack.io' } } project.ext.latestAboutLibsRelease = "10.5.0" project.ext.sentryConfigFile = new File(rootDir, "sentry.properties").getAbsoluteFile() @@ -12,6 +14,7 @@ buildscript { logLevel: "debug", flavorAware: true ] + project.ext.kotlin_version = "1.7.20" dependencies { classpath 'com.android.tools.build:gradle:7.3.1' classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${latestAboutLibsRelease}" diff --git a/settings.gradle b/settings.gradle index 5c996dc..db25883 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,7 @@ dependencyResolutionManagement { maven { url 'https://jitpack.io' } + maven { url 'https://maven.fpregistry.io/releases' } } } rootProject.name = "MagiskModuleManager"