Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca400637 authored by Fynn Godau's avatar Fynn Godau
Browse files

Load device profile data for licensing user agent

parent 080b149d
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -243,7 +243,7 @@ object ProfileManager {
        }
    }

    private fun applyProfileData(profileData: Map<String, String>) {
    fun applyProfileData(profileData: Map<String, String>) {
        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) }
+1 −0
Original line number Diff line number Diff line
@@ -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"
+6 −5
Original line number Diff line number Diff line
@@ -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)
@@ -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) {
@@ -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 -> {
@@ -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 -> {
+34 −17
Original line number Diff line number Diff line
@@ -31,21 +31,27 @@ 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;
import java.util.stream.Collectors;

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;

@@ -55,6 +61,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()
@@ -107,9 +117,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()
                )
@@ -119,13 +129,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()
@@ -134,22 +144,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);
+39 −2
Original line number Diff line number Diff line
@@ -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<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()) {
@@ -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
@@ -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