Loading vending-app/build.gradle +1 −0 Original line number Diff line number Diff line Loading @@ -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" Loading vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.java +6 −5 Original line number Diff line number Diff line Loading @@ -79,10 +79,10 @@ public abstract class LicenseChecker<D, R> { 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<Integer, R> 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<Integer, R, RemoteException> onResult) Loading Loading @@ -118,8 +118,9 @@ public abstract class LicenseChecker<D, R> { 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) { Loading Loading @@ -149,7 +150,7 @@ public abstract class LicenseChecker<D, R> { public static class V1 extends LicenseChecker<Long, Tuple<String, String>> { @Override public Request<V1Container> createRequest(String packageName, String auth, int versionCode, Long nonce, BiConsumer<Integer, Tuple<String, String>> then, public LicenseRequest<V1Container> createRequest(String packageName, String auth, int versionCode, Long nonce, BiConsumer<Integer, Tuple<String, String>> then, Response.ErrorListener errorListener) { return new LicenseRequest.V1( packageName, auth, versionCode, nonce, response -> { Loading @@ -170,7 +171,7 @@ public abstract class LicenseChecker<D, R> { public static class V2 extends LicenseChecker<Unit, String> { @Override public Request<String> createRequest(String packageName, String auth, int versionCode, Unit data, public LicenseRequest<String> createRequest(String packageName, String auth, int versionCode, Unit data, BiConsumer<Integer, String> then, Response.ErrorListener errorListener) { return new LicenseRequest.V2( packageName, auth, versionCode, response -> { Loading vending-app/src/main/java/com/android/vending/licensing/LicenseRequest.java +33 −17 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -40,12 +45,12 @@ import okio.ByteString; public abstract class LicenseRequest<T> extends Request<T> { 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<T> successListener; Loading @@ -55,6 +60,10 @@ public abstract class LicenseRequest<T> extends Request<T> { this.auth = auth; this.successListener = successListener; } @Override public Map<String, String> getHeaders() { long millis = System.currentTimeMillis(); TimestampContainer.Builder timestamp = new TimestampContainer.Builder() Loading Loading @@ -107,9 +116,9 @@ public abstract class LicenseRequest<T> extends Request<T> { .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() ) Loading @@ -119,13 +128,13 @@ public abstract class LicenseRequest<T> extends Request<T> { .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() Loading @@ -134,22 +143,29 @@ public abstract class LicenseRequest<T> extends Request<T> { .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<String, String> 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); Loading vending-app/src/main/java/com/android/vending/licensing/LicensingService.java +39 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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() { Loading @@ -58,7 +69,7 @@ public class LicensingService extends Service { private void checkLicense(long nonce, String packageName, PackageManager packageManager, ILicenseResultListener listener, Queue<Account> 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()) { Loading Loading @@ -88,7 +99,7 @@ public class LicensingService extends Service { ILicenseV2ResultListener listener, Bundle extraParams, Queue<Account> 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 Loading Loading @@ -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<String, String> 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); Loading vending-app/src/main/proto/LicenseRequest.proto +4 −4 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading
vending-app/build.gradle +1 −0 Original line number Diff line number Diff line Loading @@ -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" Loading
vending-app/src/main/java/com/android/vending/licensing/LicenseChecker.java +6 −5 Original line number Diff line number Diff line Loading @@ -79,10 +79,10 @@ public abstract class LicenseChecker<D, R> { 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<Integer, R> 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<Integer, R, RemoteException> onResult) Loading Loading @@ -118,8 +118,9 @@ public abstract class LicenseChecker<D, R> { 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) { Loading Loading @@ -149,7 +150,7 @@ public abstract class LicenseChecker<D, R> { public static class V1 extends LicenseChecker<Long, Tuple<String, String>> { @Override public Request<V1Container> createRequest(String packageName, String auth, int versionCode, Long nonce, BiConsumer<Integer, Tuple<String, String>> then, public LicenseRequest<V1Container> createRequest(String packageName, String auth, int versionCode, Long nonce, BiConsumer<Integer, Tuple<String, String>> then, Response.ErrorListener errorListener) { return new LicenseRequest.V1( packageName, auth, versionCode, nonce, response -> { Loading @@ -170,7 +171,7 @@ public abstract class LicenseChecker<D, R> { public static class V2 extends LicenseChecker<Unit, String> { @Override public Request<String> createRequest(String packageName, String auth, int versionCode, Unit data, public LicenseRequest<String> createRequest(String packageName, String auth, int versionCode, Unit data, BiConsumer<Integer, String> then, Response.ErrorListener errorListener) { return new LicenseRequest.V2( packageName, auth, versionCode, response -> { Loading
vending-app/src/main/java/com/android/vending/licensing/LicenseRequest.java +33 −17 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -40,12 +45,12 @@ import okio.ByteString; public abstract class LicenseRequest<T> extends Request<T> { 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<T> successListener; Loading @@ -55,6 +60,10 @@ public abstract class LicenseRequest<T> extends Request<T> { this.auth = auth; this.successListener = successListener; } @Override public Map<String, String> getHeaders() { long millis = System.currentTimeMillis(); TimestampContainer.Builder timestamp = new TimestampContainer.Builder() Loading Loading @@ -107,9 +116,9 @@ public abstract class LicenseRequest<T> extends Request<T> { .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() ) Loading @@ -119,13 +128,13 @@ public abstract class LicenseRequest<T> extends Request<T> { .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() Loading @@ -134,22 +143,29 @@ public abstract class LicenseRequest<T> extends Request<T> { .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<String, String> 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); Loading
vending-app/src/main/java/com/android/vending/licensing/LicensingService.java +39 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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() { Loading @@ -58,7 +69,7 @@ public class LicensingService extends Service { private void checkLicense(long nonce, String packageName, PackageManager packageManager, ILicenseResultListener listener, Queue<Account> 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()) { Loading Loading @@ -88,7 +99,7 @@ public class LicensingService extends Service { ILicenseV2ResultListener listener, Bundle extraParams, Queue<Account> 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 Loading Loading @@ -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<String, String> 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); Loading
vending-app/src/main/proto/LicenseRequest.proto +4 −4 Original line number Diff line number Diff line Loading @@ -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 { Loading