11package com .fox2code .mmm .androidacy ;
22
3+ import android .annotation .SuppressLint ;
34import android .content .SharedPreferences ;
45import android .util .Log ;
56import android .widget .Toast ;
1617import com .fox2code .mmm .utils .Http ;
1718import com .fox2code .mmm .utils .HttpException ;
1819import com .fox2code .mmm .utils .PropUtils ;
19- import com .topjohnwu .superuser .internal .UiThreadHandler ;
2020
2121import org .json .JSONArray ;
2222import org .json .JSONException ;
2323import org .json .JSONObject ;
2424
2525import java .io .File ;
2626import java .io .IOException ;
27- import java .nio .charset .StandardCharsets ;
2827import java .util .ArrayList ;
2928import java .util .Iterator ;
3029import java .util .List ;
@@ -44,9 +43,9 @@ public final class AndroidacyRepoData extends RepoData {
4443
4544 private final boolean testMode ;
4645 private final String host ;
46+ public String token = MainApplication .getINSTANCE ().getSharedPreferences ("androidacy" , 0 ).getString ("pref_androidacy_api_token" , null );
4747 // Avoid spamming requests to Androidacy
4848 private long androidacyBlockade = 0 ;
49- public String token = this .cachedPreferences .getString ("pref_androidacy_api_token" , null );
5049
5150 public AndroidacyRepoData (File cacheRoot , SharedPreferences cachedPreferences , boolean testMode ) {
5251 super (testMode ? RepoManager .ANDROIDACY_TEST_MAGISK_REPO_ENDPOINT : RepoManager .ANDROIDACY_MAGISK_REPO_ENDPOINT , cacheRoot , cachedPreferences );
@@ -76,14 +75,65 @@ private static String filterURL(String url) {
7675 return url ;
7776 }
7877
78+ // Generates a unique device ID. This is used to identify the device in the API for rate
79+ // limiting and fraud detection.
80+ public static String generateDeviceId () {
81+ // Try to get the device ID from the shared preferences
82+ SharedPreferences sharedPreferences = MainApplication .getINSTANCE ().getSharedPreferences ("androidacy" , 0 );
83+ String deviceIdPref = sharedPreferences .getString ("device_id" , null );
84+ if (deviceIdPref != null ) {
85+ return deviceIdPref ;
86+ } 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
116+ SharedPreferences .Editor editor = sharedPreferences .edit ();
117+ editor .putString ("device_id" , hexString .toString ());
118+ 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+ }
125+ }
126+ }
127+
79128 public boolean isValidToken (String token ) throws IOException {
129+ String deviceId = generateDeviceId ();
80130 try {
81- Http .doHttpGet ("https://" + this .host + "/auth/me?token=" + token , false );
131+ Http .doHttpGet ("https://" + this .host + "/auth/me?token=" + token + "&device_id=" + deviceId , false );
82132 } catch (HttpException e ) {
83133 if (e .getErrorCode () == 401 ) {
84134 Log .w (TAG , "Invalid token, resetting..." );
85135 // Remove saved preference
86- SharedPreferences .Editor editor = this . cachedPreferences .edit ();
136+ SharedPreferences .Editor editor = MainApplication . getINSTANCE (). getSharedPreferences ( "androidacy" , 0 ) .edit ();
87137 editor .remove ("pref_androidacy_api_token" );
88138 editor .apply ();
89139 return false ;
@@ -110,6 +160,7 @@ protected boolean prepare() {
110160 }*/
111161 return false ;
112162 }
163+ String deviceId = generateDeviceId ();
113164 long time = System .currentTimeMillis ();
114165 if (this .androidacyBlockade > time ) return false ;
115166 this .androidacyBlockade = time + 30_000L ;
@@ -137,8 +188,8 @@ protected boolean prepare() {
137188 if (token == null ) {
138189 try {
139190 Log .i (TAG , "Requesting new token..." );
140- // POST request to https://production-api.androidacy.com/auth/register
141- token = new String (Http .doHttpPost ("https://" + this .host + "/auth/register" , "{\" foxmmm \" : \" true \" }" , false ), StandardCharsets . UTF_8 );
191+ // POST json request to https://production-api.androidacy.com/auth/register
192+ token = new String (Http .doHttpPost ("https://" + this .host + "/auth/register" , "{\" device_id \" :\" " + deviceId + " \" }" , false ));
142193 // Parse token
143194 try {
144195 JSONObject jsonObject = new JSONObject (token );
@@ -157,7 +208,7 @@ protected boolean prepare() {
157208 return false ;
158209 }
159210 // Save token to shared preference
160- SharedPreferences .Editor editor = this . cachedPreferences .edit ();
211+ SharedPreferences .Editor editor = MainApplication . getINSTANCE (). getSharedPreferences ( "androidacy" , 0 ) .edit ();
161212 editor .putString ("pref_androidacy_api_token" , token );
162213 editor .apply ();
163214 } catch (Exception e ) {
@@ -289,7 +340,8 @@ public boolean tryLoadMetadata(RepoModule repoModule) {
289340
290341 @ Override
291342 public String getUrl () {
292- return this .token == null ? this .url : this .url + "?token=" + this .token ;
343+ return this .token == null ? this .url :
344+ this .url + "?token=" + this .token + "&v=" + BuildConfig .VERSION_CODE + "&c=" + BuildConfig .VERSION_NAME + "&device_id=" + generateDeviceId ();
293345 }
294346
295347 private String injectToken (String url ) {
@@ -307,13 +359,21 @@ private String injectToken(String url) {
307359 }
308360 }
309361 String token = "token=" + this .token ;
362+ String deviceId = "device_id=" + generateDeviceId ();
310363 if (!url .contains (token )) {
311364 if (url .lastIndexOf ('/' ) < url .lastIndexOf ('?' )) {
312365 return url + '&' + token ;
313366 } else {
314367 return url + '?' + token ;
315368 }
316369 }
370+ if (!url .contains (deviceId )) {
371+ if (url .lastIndexOf ('/' ) < url .lastIndexOf ('?' )) {
372+ return url + '&' + deviceId ;
373+ } else {
374+ return url + '?' + deviceId ;
375+ }
376+ }
317377 return url ;
318378 }
319379
0 commit comments