diff --git a/play-services-base/core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt b/play-services-base/core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt index d367cb34dcf58de2b6b63d8187b386074a4e0c9b..e8ba505f6b62e997f7d4e6b12ef0e031434be24b 100644 --- a/play-services-base/core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt +++ b/play-services-base/core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt @@ -243,7 +243,7 @@ object ProfileManager { } } - private fun applyProfileData(profileData: Map) { + fun applyProfileData(profileData: Map) { fun applyStringField(key: String, valueSetter: (String) -> Unit) = profileData[key]?.let { valueSetter(it) } fun applyIntField(key: String, valueSetter: (Int) -> Unit) = profileData[key]?.toIntOrNull()?.let { valueSetter(it) } fun applyLongField(key: String, valueSetter: (Long) -> Unit) = profileData[key]?.toLongOrNull()?.let { valueSetter(it) } diff --git a/vending-app/build.gradle b/vending-app/build.gradle index 6a2023d6bff8cb09708dc15ad47c5f55d630b94a..12efd905a408e3926d20e38b3aca30adad22db94 100644 --- a/vending-app/build.gradle +++ b/vending-app/build.gradle @@ -60,6 +60,7 @@ android { dependencies { implementation project(':fake-signature') implementation project(':play-services-auth') + implementation project(':play-services-base-core') implementation "com.squareup.wire:wire-runtime:$wireVersion" implementation "com.android.volley:volley:$volleyVersion" diff --git a/vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.java b/vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.java index ff9992f7df6b0370b18b54bea6975f18cdc9925c..6e4dcbb984c293ad7bc6795a07c761973286a534 100644 --- a/vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.java +++ b/vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.java @@ -79,10 +79,10 @@ public abstract class LicenseChecker { static final String AUTH_TOKEN_SCOPE = "oauth2:https://www.googleapis.com/auth/googleplay"; - public abstract Request createRequest(String packageName, String auth, int versionCode, D data, + public abstract LicenseRequest createRequest(String packageName, String auth, int versionCode, D data, BiConsumer then, Response.ErrorListener errorListener); - public void checkLicense(Account account, AccountManager accountManager, + public void checkLicense(Account account, AccountManager accountManager, String androidId, String packageName, PackageManager packageManager, RequestQueue queue, D queryData, BiConsumerWithException onResult) @@ -118,8 +118,9 @@ public abstract class LicenseChecker { future -> { try { String auth = future.getResult().getString(KEY_AUTHTOKEN); - Request request = createRequest(packageName, auth, + LicenseRequest request = createRequest(packageName, auth, versionCode, queryData, onRequestFinished, onRequestError); + request.ANDROID_ID = Long.decode("0x" + androidId); request.setShouldCache(false); queue.add(request); } catch (AuthenticatorException | IOException | OperationCanceledException e) { @@ -149,7 +150,7 @@ public abstract class LicenseChecker { public static class V1 extends LicenseChecker> { @Override - public Request createRequest(String packageName, String auth, int versionCode, Long nonce, BiConsumer> then, + public LicenseRequest createRequest(String packageName, String auth, int versionCode, Long nonce, BiConsumer> then, Response.ErrorListener errorListener) { return new LicenseRequest.V1( packageName, auth, versionCode, nonce, response -> { @@ -170,7 +171,7 @@ public abstract class LicenseChecker { public static class V2 extends LicenseChecker { @Override - public Request createRequest(String packageName, String auth, int versionCode, Unit data, + public LicenseRequest createRequest(String packageName, String auth, int versionCode, Unit data, BiConsumer then, Response.ErrorListener errorListener) { return new LicenseRequest.V2( packageName, auth, versionCode, response -> { diff --git a/vending-app/src/main/java/com/android/vending/licensing/LicenseRequest.java b/vending-app/src/main/java/com/android/vending/licensing/LicenseRequest.java index 08d6e28ab3a615318f58ec6659781e3b35fc4ef5..843716f086f5fa0cd71eb25fb1ef5fdf8b011fed 100644 --- a/vending-app/src/main/java/com/android/vending/licensing/LicenseRequest.java +++ b/vending-app/src/main/java/com/android/vending/licensing/LicenseRequest.java @@ -31,8 +31,13 @@ import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; +import com.google.android.gms.common.BuildConfig; + +import org.microg.gms.profile.Build; import java.io.IOException; +import java.net.URLEncoder; +import java.util.Arrays; import java.util.Map; import java.util.UUID; @@ -40,12 +45,12 @@ import okio.ByteString; public abstract class LicenseRequest extends Request { - private final String xPsRh; private final String auth; private static final String TAG = "FakeLicenseRequest"; private static final int BASE64_FLAGS = Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING; - private static final long ANDROID_ID = 1; + long ANDROID_ID = 1; + private static final String FINSKY_VERSION = "Finsky/37.5.24-29%20%5B0%5D%20%5BPR%5D%20565477504"; private final Response.Listener successListener; @@ -55,6 +60,10 @@ public abstract class LicenseRequest extends Request { this.auth = auth; this.successListener = successListener; + } + + @Override + public Map getHeaders() { long millis = System.currentTimeMillis(); TimestampContainer.Builder timestamp = new TimestampContainer.Builder() @@ -107,9 +116,9 @@ public abstract class LicenseRequest extends Request { .deviceMeta(new DeviceMeta.Builder() .android( new AndroidVersionMeta.Builder() - .androidSdk(0) - .buildNumber("") - .androidVersion("") + .androidSdk(Build.VERSION.SDK_INT) + .buildNumber(Build.ID) + .androidVersion(Build.VERSION.RELEASE) .unknown(0) .build() ) @@ -119,13 +128,13 @@ public abstract class LicenseRequest extends Request { .build() ) .userAgent(new UserAgent.Builder() - .deviceProductName("") - .deviceSoc("") - .deviceModelName("") - .finskyVersion("") - .deviceName("") + .deviceName(Build.DEVICE) + .deviceHardware(Build.HARDWARE) + .deviceModelName(Build.MODEL) + .finskyVersion(FINSKY_VERSION) + .deviceProductName(Build.MODEL) .androidId(ANDROID_ID) // must not be 0 - .deviceSignature("") + .buildFingerprint(Build.FINGERPRINT) .build() ) .uuid(new Uuid.Builder() @@ -134,22 +143,29 @@ public abstract class LicenseRequest extends Request { .build() ) .build().encode(); - this.xPsRh = new String(Base64.encode(Util.encodeGzip(header), BASE64_FLAGS)); - - //Log.d(TAG, "Product " + Build.PRODUCT + ", Board " + Build.BOARD + " Model " + Build.MODEL + " Device " + Build.DEVICE); + String xPsRh = new String(Base64.encode(Util.encodeGzip(header), BASE64_FLAGS)); Log.v(TAG, "X-PS-RH: " + xPsRh); - } - @Override - public Map getHeaders() { + String userAgent = FINSKY_VERSION + " (api=3,versionCode=" + BuildConfig.VERSION_CODE + ",sdk=" + Build.VERSION.SDK + + ",device=" + encodeString(Build.DEVICE) + ",hardware=" + encodeString(Build.HARDWARE) + ",product=" + encodeString(Build.PRODUCT) + + ",platformVersionRelease=" + encodeString(Build.VERSION.RELEASE) + ",model=" + encodeString(Build.MODEL) + ",buildId=" + encodeString(Build.ID) + + ",isWideScreen=" + 0 + ",supportedAbis=" + String.join(";", Build.SUPPORTED_ABIS) + ")"; + Log.v(TAG, "User-Agent: " + userAgent); + return Map.of( "X-PS-RH", xPsRh, + "User-Agent", userAgent, "Authorization", "Bearer " + auth, + "Accept-Language", "en-US", "Connection", "Keep-Alive" ); } + private static String encodeString(String s) { + return URLEncoder.encode(s).replace("+", "%20"); + } + @Override protected void deliverResponse(T response) { successListener.onResponse(response); diff --git a/vending-app/src/main/java/com/android/vending/licensing/LicensingService.java b/vending-app/src/main/java/com/android/vending/licensing/LicensingService.java index 8b58ca22edb0a624d22d553030be29cb93bda5ef..c099bbd03afbed0f8ad986ae6f020971eeecfa52 100644 --- a/vending-app/src/main/java/com/android/vending/licensing/LicensingService.java +++ b/vending-app/src/main/java/com/android/vending/licensing/LicensingService.java @@ -13,18 +13,25 @@ import android.app.Service; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; import org.microg.gms.auth.AuthConstants; +import org.microg.gms.profile.Build; +import org.microg.gms.profile.ProfileManager; import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.Queue; import kotlin.Unit; @@ -37,6 +44,10 @@ public class LicensingService extends Service { private static final String KEY_V2_RESULT_JWT = "LICENSE_DATA"; + private static final Uri PROFILE_PROVIDER = Uri.parse("content://com.google.android.gms.microg.profile"); + + private String androidId; + private final ILicensingService.Stub mLicenseService = new ILicensingService.Stub() { @@ -58,7 +69,7 @@ public class LicensingService extends Service { private void checkLicense(long nonce, String packageName, PackageManager packageManager, ILicenseResultListener listener, Queue remainingAccounts) throws RemoteException { new LicenseChecker.V1().checkLicense( - remainingAccounts.poll(), accountManager, packageName, packageManager, + remainingAccounts.poll(), accountManager, androidId, packageName, packageManager, queue, nonce, (responseCode, stringTuple) -> { if (responseCode != LICENSED && !remainingAccounts.isEmpty()) { @@ -88,7 +99,7 @@ public class LicensingService extends Service { ILicenseV2ResultListener listener, Bundle extraParams, Queue remainingAccounts) throws RemoteException { new LicenseChecker.V2().checkLicense( - remainingAccounts.poll(), accountManager, packageName, packageManager, queue, Unit.INSTANCE, + remainingAccounts.poll(), accountManager, androidId, packageName, packageManager, queue, Unit.INSTANCE, (responseCode, data) -> { /* * Suppress failures on V2. V2 is commonly used by free apps whose checker @@ -127,6 +138,32 @@ public class LicensingService extends Service { }; public IBinder onBind(Intent intent) { + + + Cursor cursor = null; + try { + cursor = getContentResolver().query( + PROFILE_PROVIDER, null, null, null, null + ); + + if (cursor == null || cursor.getColumnCount() != 2) { + Log.e(TAG, "profile provider not available"); + } else { + Map profileData = new HashMap<>(); + while (cursor.moveToNext()) { + profileData.put(cursor.getString(0), cursor.getString(1)); + } + ProfileManager.INSTANCE.applyProfileData(profileData); + } + + } finally { + if (cursor != null) { + cursor.close(); + } + } + + androidId = String.valueOf(Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID)); + queue = Volley.newRequestQueue(this); accountManager = AccountManager.get(this); notificationRunnable = new LicenseServiceNotificationRunnable(this); diff --git a/vending-app/src/main/proto/LicenseRequest.proto b/vending-app/src/main/proto/LicenseRequest.proto index da8747c2cdb743c647a10bc83e4eec6666d780fa..dc0b71339e9353ae576a0047ff298be6654f8758 100644 --- a/vending-app/src/main/proto/LicenseRequest.proto +++ b/vending-app/src/main/proto/LicenseRequest.proto @@ -56,13 +56,13 @@ message UnknownByte12 { message UserAgent { // The names of these attributes are vague guesses and should be adapted if needed. - optional string deviceProductName = 1; // e.g. "OnePlusNord" - optional string deviceSoc = 2; // e.g. "qcom" + optional string deviceName = 1; // e.g. "OnePlusNord" + optional string deviceHardware = 2; // e.g. "qcom" optional string deviceModelName = 3; // e.g. "OnePlus Nord" optional string finskyVersion = 4; // e.g. "Finsky/37.5.24-29%20%5B0%5D%20%5BPR%5D%20565477504" - optional string deviceName = 5; // e.g. "OnePlusNord"; difference to 1 not yet clear + optional string deviceProductName = 5; // e.g. "OnePlusNord" optional uint64 androidId = 6; - optional string deviceSignature = 7; // e.g. "google/walleye/walleye:8.1.0/OPM1.171019.011/4448085:user/release-keys" + optional string buildFingerprint = 7; // e.g. "google/walleye/walleye:8.1.0/OPM1.171019.011/4448085:user/release-keys" } message Uuid {