From 10de88b89f7f0c60834be300cf3f09bb6df7cdac Mon Sep 17 00:00:00 2001 From: Marvin W Date: Tue, 18 Jan 2022 18:54:05 +0100 Subject: [PATCH] Add new Auth API features --- .../gms/auth/api/internal/IAuthCallbacks.aidl | 8 + .../gms/auth/api/internal/IAuthService.aidl | 11 ++ .../gms/auth/api/proxy/ProxyRequest.aidl | 3 + .../gms/auth/api/proxy/ProxyResponse.aidl | 3 + .../gms/auth/appcert/IAppCertService.aidl | 6 + .../gms/auth/api/proxy/ProxyRequest.java | 41 +++++ .../gms/auth/api/proxy/ProxyResponse.java | 30 ++++ .../src/main/proto/appcert.proto | 33 ++++ .../microg/gms/auth/appcert/AppCertManager.kt | 170 ++++++++++++++++++ .../microg/gms/auth/appcert/AppCertService.kt | 42 +++++ .../CredentialPickerActivity.kt | 4 +- .../{ => credentials}/CredentialsService.kt | 9 +- .../microg/gms/auth/proxy/AuthProxyService.kt | 63 +++++++ 13 files changed, 418 insertions(+), 5 deletions(-) create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthCallbacks.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthService.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyRequest.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyResponse.aidl create mode 100644 play-services-api/src/main/aidl/com/google/android/gms/auth/appcert/IAppCertService.aidl create mode 100644 play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyRequest.java create mode 100644 play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyResponse.java create mode 100644 play-services-core-proto/src/main/proto/appcert.proto create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt rename play-services-core/src/main/kotlin/org/microg/gms/auth/{ => credentials}/CredentialPickerActivity.kt (94%) rename play-services-core/src/main/kotlin/org/microg/gms/auth/{ => credentials}/CredentialsService.kt (81%) create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt diff --git a/play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthCallbacks.aidl b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthCallbacks.aidl new file mode 100644 index 00000000..ae8e79c5 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthCallbacks.aidl @@ -0,0 +1,8 @@ +package com.google.android.gms.auth.api.internal; + +import com.google.android.gms.auth.api.proxy.ProxyResponse; + +interface IAuthCallbacks { + void onProxyResponse(in ProxyResponse response) = 0; + void onSpatulaHeader(String spatulaHeader) = 1; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthService.aidl b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthService.aidl new file mode 100644 index 00000000..a5f6a537 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/internal/IAuthService.aidl @@ -0,0 +1,11 @@ +package com.google.android.gms.auth.api.internal; + +import com.google.android.gms.auth.api.internal.IAuthCallbacks; +//import com.google.android.gms.auth.api.proxy.ProxyGrpcRequest; +import com.google.android.gms.auth.api.proxy.ProxyRequest; + +interface IAuthService { + void performProxyRequest(IAuthCallbacks callbacks, in ProxyRequest request) = 0; +// void performProxyGrpcRequest(IAuthCallback callbacks, in ProxyGrpcRequest request) = 1; + void getSpatulaHeader(IAuthCallbacks callbacks) = 2; +} diff --git a/play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyRequest.aidl b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyRequest.aidl new file mode 100644 index 00000000..fa5885f8 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyRequest.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.auth.api.proxy; + +parcelable ProxyRequest; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyResponse.aidl b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyResponse.aidl new file mode 100644 index 00000000..eae21f3c --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/auth/api/proxy/ProxyResponse.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.auth.api.proxy; + +parcelable ProxyResponse; diff --git a/play-services-api/src/main/aidl/com/google/android/gms/auth/appcert/IAppCertService.aidl b/play-services-api/src/main/aidl/com/google/android/gms/auth/appcert/IAppCertService.aidl new file mode 100644 index 00000000..ee7f7338 --- /dev/null +++ b/play-services-api/src/main/aidl/com/google/android/gms/auth/appcert/IAppCertService.aidl @@ -0,0 +1,6 @@ +package com.google.android.gms.auth.appcert; + +interface IAppCertService { + boolean fetchDeviceKey() = 0; + String getSpatulaHeader(String packageName) = 1; +} diff --git a/play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyRequest.java b/play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyRequest.java new file mode 100644 index 00000000..71270ebb --- /dev/null +++ b/play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyRequest.java @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.auth.api.proxy; + +import android.os.Bundle; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class ProxyRequest extends AutoSafeParcelable { + public static final int HTTP_METHOD_GET = 0; + public static final int HTTP_METHOD_POST = 1; + public static final int HTTP_METHOD_PUT = 2; + public static final int HTTP_METHOD_DELETE = 3; + public static final int HTTP_METHOD_HEAD = 4; + public static final int HTTP_METHOD_OPTIONS = 5; + public static final int HTTP_METHOD_TRACE = 6; + public static final int HTTP_METHOD_PATCH = 7; + + @Field(1000) + private int versionCode = 2; + @Field(1) + public String url; + @Field(2) + public int httpMethod; + @Field(3) + public long timeoutMillis; + @Field(4) + public byte[] body; + @Field(5) + public Bundle headers; + + @Override + public String toString() { + return url; + } + + public static final Creator CREATOR = new AutoCreator<>(ProxyRequest.class); +} diff --git a/play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyResponse.java b/play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyResponse.java new file mode 100644 index 00000000..951210cb --- /dev/null +++ b/play-services-api/src/main/java/com/google/android/gms/auth/api/proxy/ProxyResponse.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.google.android.gms.auth.api.proxy; + +import android.app.PendingIntent; +import android.os.Bundle; + +import org.microg.safeparcel.AutoSafeParcelable; + +public class ProxyResponse extends AutoSafeParcelable { + public static final int STATUS_CODE_NO_CONNECTION = -1; + + @Field(1000) + private int versionCode = 1; + @Field(1) + public int gmsStatusCode; + @Field(2) + public PendingIntent recoveryAction; + @Field(3) + public int httpStatusCode; + @Field(4) + public Bundle headers; + @Field(5) + public byte[] body; + + public static final Creator CREATOR = new AutoCreator<>(ProxyResponse.class); +} diff --git a/play-services-core-proto/src/main/proto/appcert.proto b/play-services-core-proto/src/main/proto/appcert.proto new file mode 100644 index 00000000..5a9bc815 --- /dev/null +++ b/play-services-core-proto/src/main/proto/appcert.proto @@ -0,0 +1,33 @@ +option java_package = "org.microg.gms.auth.appcert"; +option java_outer_classname = "AppCertProto"; + +message DeviceKeyRequest { + optional string droidGuardResult = 1; + optional uint64 androidId = 2; + optional uint64 sessionId = 3; + message VersionInfo { + optional uint32 sdkVersion = 1; + optional uint32 gmsVersion = 2; + } + optional VersionInfo versionInfo = 4; + optional string token = 5; +} + +message DeviceKey { + optional uint64 keyId = 1; + optional uint64 deviceId = 3; + optional bytes macSecret = 4; + optional bytes keyCert = 5; +} + +message SpatulaHeaderProto { + message PackageInfo { + optional string packageName = 1; + optional string packageCertificateHash = 3; + } + optional PackageInfo packageInfo = 1; + optional bytes hmac = 2; + optional uint64 deviceId = 3; + optional uint64 keyId = 4; + optional bytes keyCert = 5; +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt new file mode 100644 index 00000000..cc38d73c --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertManager.kt @@ -0,0 +1,170 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.auth.appcert + +import android.content.Context +import android.database.Cursor +import android.os.SystemClock +import android.util.Base64 +import android.util.Log +import com.android.volley.NetworkResponse +import com.android.volley.Request +import com.android.volley.Response +import com.android.volley.VolleyError +import com.android.volley.toolbox.Volley +import com.google.android.gms.BuildConfig +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import okio.ByteString.Companion.of +import org.microg.gms.checkin.LastCheckinInfo +import org.microg.gms.common.Constants +import org.microg.gms.common.PackageUtils +import org.microg.gms.droidguard.core.DroidGuardResultCreator +import org.microg.gms.gcm.GcmConstants +import org.microg.gms.gcm.GcmDatabase +import org.microg.gms.gcm.RegisterRequest +import org.microg.gms.gcm.completeRegisterRequest +import org.microg.gms.profile.Build +import org.microg.gms.profile.ProfileManager +import org.microg.gms.settings.SettingsContract.CheckIn +import org.microg.gms.settings.SettingsContract.getSettings +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec +import kotlin.random.Random + +class AppCertManager(private val context: Context) { + private val queue = Volley.newRequestQueue(context) + + suspend fun fetchDeviceKey(): Boolean { + ProfileManager.ensureInitialized(context) + deviceKeyLock.withLock { + try { + val elapsedRealtime = SystemClock.elapsedRealtime() + if (elapsedRealtime - deviceKeyCacheTime < DEVICE_KEY_TIMEOUT) { + return deviceKey != null + } + Log.w(TAG, "DeviceKeys for app certifications are experimental") + deviceKeyCacheTime = elapsedRealtime + val lastCheckinInfo = LastCheckinInfo.read(context) + val androidId = lastCheckinInfo.androidId + val sessionId = Random.nextLong() + val data = hashMapOf( + "dg_androidId" to androidId.toString(16), + "dg_session" to sessionId.toString(16), + "dg_gmsCoreVersion" to BuildConfig.VERSION_CODE.toString(), + "dg_sdkVersion" to Build.VERSION.SDK_INT.toString() + ) + val droidGuardResult = try { + Base64.encodeToString(DroidGuardResultCreator.getResult(context, "devicekey", data), Base64.NO_WRAP) + } catch (e: Exception) { + null + } + val token = completeRegisterRequest(context, GcmDatabase(context), RegisterRequest().build(context) + .checkin(lastCheckinInfo) + .app("com.google.android.gms", Constants.GMS_PACKAGE_SIGNATURE_SHA1, BuildConfig.VERSION_CODE) + .sender(REGISTER_SENDER) + .extraParam("subscription", REGISTER_SUBSCIPTION) + .extraParam("X-subscription", REGISTER_SUBSCIPTION) + .extraParam("subtype", REGISTER_SUBTYPE) + .extraParam("X-subtype", REGISTER_SUBTYPE) + .extraParam("scope", REGISTER_SCOPE)) + .getString(GcmConstants.EXTRA_REGISTRATION_ID) + val request = DeviceKeyRequest( + droidGuardResult = droidGuardResult, + androidId = lastCheckinInfo.androidId, + sessionId = sessionId, + versionInfo = DeviceKeyRequest.VersionInfo(Build.VERSION.SDK_INT, BuildConfig.VERSION_CODE), + token = token + ) + Log.d(TAG, "Request: ${request.toString().chunked(128).joinToString("\n")}") + val deferredResponse = CompletableDeferred() + queue.add(object : Request(Method.POST, "https://android.googleapis.com/auth/devicekey", null) { + override fun getBody(): ByteArray = request.encode() + + override fun getBodyContentType(): String = "application/octet-stream" + + override fun parseNetworkResponse(response: NetworkResponse): Response { + return if (response.statusCode == 200) { + Response.success(response.data, null) + } else { + Response.success(null, null) + } + } + + override fun deliverError(error: VolleyError) { + Log.d(TAG, "Error: ${Base64.encodeToString(error.networkResponse.data, 2)}") + deferredResponse.complete(null) + } + + override fun deliverResponse(response: ByteArray?) { + deferredResponse.complete(response) + } + + override fun getHeaders(): Map { + return mapOf( + "User-Agent" to "GoogleAuth/1.4 (${Build.DEVICE} ${Build.ID}); gzip", + "content-type" to "application/octet-stream", + "app" to "com.google.android.gms", + "device" to androidId.toString(16) + ) + } + }) + val deviceKeyBytes = deferredResponse.await() ?: return false + deviceKey = DeviceKey.ADAPTER.decode(deviceKeyBytes) + Log.d(TAG, "Response: $deviceKey") + return true + } catch (e: Exception) { + Log.w(TAG, e) + return false + } + } + } + + suspend fun getSpatulaHeader(packageName: String): String? { + val deviceKey = deviceKey ?: if (fetchDeviceKey()) deviceKey else null + val packageCertificateHash = Base64.encodeToString(PackageUtils.firstSignatureDigestBytes(context, packageName), Base64.NO_WRAP) + val proto = if (deviceKey != null) { + val macSecret = deviceKey.macSecret?.toByteArray() + if (macSecret == null) { + Log.w(TAG, "Invalid device key: $deviceKey") + return null + } + val mac = Mac.getInstance("HMACSHA256") + mac.init(SecretKeySpec(macSecret, "HMACSHA256")) + val hmac = mac.doFinal("$packageName$packageCertificateHash".toByteArray()) + SpatulaHeaderProto( + packageInfo = SpatulaHeaderProto.PackageInfo(packageName, packageCertificateHash), + hmac = of(*hmac), + deviceId = deviceKey.deviceId, + keyId = deviceKey.keyId, + keyCert = deviceKey.keyCert ?: of() + ) + } else { + Log.d(TAG, "Using fallback spatula header based on Android ID") + val androidId = getSettings(context, CheckIn.getContentUri(context), arrayOf(CheckIn.ANDROID_ID, CheckIn.SECURITY_TOKEN)) { cursor: Cursor -> cursor.getLong(0) } + SpatulaHeaderProto( + packageInfo = SpatulaHeaderProto.PackageInfo(packageName, packageCertificateHash), + deviceId = androidId + ) + } + Log.d(TAG, "Spatula Header: $proto") + return Base64.encodeToString(proto.encode(), Base64.NO_WRAP) + } + + companion object { + private const val TAG = "AppCertManager" + private const val DEVICE_KEY_TIMEOUT = 60 * 60 * 1000L + private const val REGISTER_SENDER = "745476177629" + private const val REGISTER_SUBTYPE = "745476177629" + private const val REGISTER_SUBSCIPTION = "745476177629" + private const val REGISTER_SCOPE = "DeviceKeyRequest" + private val deviceKeyLock = Mutex() + private var deviceKey: DeviceKey? = null + private var deviceKeyCacheTime = 0L + } +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt new file mode 100644 index 00000000..e73017e2 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/appcert/AppCertService.kt @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.auth.appcert + +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.IBinder +import android.os.Parcel +import android.util.Log +import com.google.android.gms.auth.appcert.IAppCertService +import kotlinx.coroutines.runBlocking +import org.microg.gms.common.PackageUtils +import org.microg.gms.utils.warnOnTransactionIssues + +private const val TAG = "AppCertService" + +class AppCertService : Service() { + override fun onBind(intent: Intent): IBinder { + Log.d(TAG, "onBind: $intent") + return AppCertServiceImpl(this).asBinder() + } +} + +class AppCertServiceImpl(private val context: Context) : IAppCertService.Stub() { + private val manager = AppCertManager(context) + + override fun fetchDeviceKey(): Boolean { + PackageUtils.assertExtendedAccess(context) + return runBlocking { manager.fetchDeviceKey() } + } + + override fun getSpatulaHeader(packageName: String): String? { + PackageUtils.assertExtendedAccess(context) + return runBlocking { manager.getSpatulaHeader(packageName) } + } + + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) } +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialPickerActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialPickerActivity.kt similarity index 94% rename from play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialPickerActivity.kt rename to play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialPickerActivity.kt index e8e3fac3..ba1e9c4f 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialPickerActivity.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialPickerActivity.kt @@ -1,9 +1,9 @@ /* - * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-FileCopyrightText: 2022 microG Project Team * SPDX-License-Identifier: Apache-2.0 */ -package org.microg.gms.auth +package org.microg.gms.auth.credentials import android.app.Activity import android.os.Bundle diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialsService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt similarity index 81% rename from play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialsService.kt rename to play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt index 6f571df3..adc0370b 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/auth/CredentialsService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/credentials/CredentialsService.kt @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-FileCopyrightText: 2022 microG Project Team * SPDX-License-Identifier: Apache-2.0 */ -package org.microg.gms.auth +package org.microg.gms.auth.credentials import android.os.Bundle +import android.os.Parcel import android.util.Log import com.google.android.gms.auth.api.credentials.CredentialRequest import com.google.android.gms.auth.api.credentials.internal.* @@ -15,8 +16,9 @@ import com.google.android.gms.common.internal.GetServiceRequest import com.google.android.gms.common.internal.IGmsCallbacks import org.microg.gms.BaseService import org.microg.gms.common.GmsService +import org.microg.gms.utils.warnOnTransactionIssues -const val TAG = "GmsCredentials" +private const val TAG = "CredentialService" class CredentialsService : BaseService(TAG, GmsService.CREDENTIALS) { override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) { @@ -50,4 +52,5 @@ class CredentialsServiceImpl : ICredentialsService.Stub() { callbacks.onStatus(Status.SUCCESS) } + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) } } diff --git a/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt b/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt new file mode 100644 index 00000000..e1cedd59 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/auth/proxy/AuthProxyService.kt @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2022 microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.auth.proxy + +import android.content.Context +import android.os.Bundle +import android.os.Parcel +import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import com.google.android.gms.auth.api.internal.IAuthCallbacks +import com.google.android.gms.auth.api.internal.IAuthService +import com.google.android.gms.auth.api.proxy.ProxyRequest +import com.google.android.gms.auth.api.proxy.ProxyResponse +import com.google.android.gms.common.api.CommonStatusCodes +import com.google.android.gms.common.internal.GetServiceRequest +import com.google.android.gms.common.internal.IGmsCallbacks +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.microg.gms.BaseService +import org.microg.gms.auth.appcert.AppCertManager +import org.microg.gms.common.GmsService +import org.microg.gms.common.PackageUtils +import org.microg.gms.utils.warnOnTransactionIssues + +private const val TAG = "AuthProxyService" + +class AuthProxyService : BaseService(TAG, GmsService.AUTH_PROXY) { + override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) { + val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName) + ?: throw IllegalArgumentException("Missing package name") + val consumerPackageName = request.extras.getString("consumerPkg") + if (consumerPackageName != null) PackageUtils.assertExtendedAccess(this) + val serviceImpl = AuthServiceImpl(this, lifecycle, consumerPackageName ?: packageName) + callback.onPostInitComplete(CommonStatusCodes.SUCCESS, serviceImpl, Bundle()) + } +} + +class AuthServiceImpl(private val context: Context, private val lifecycle: Lifecycle, private val packageName: String) : IAuthService.Stub(), LifecycleOwner { + override fun performProxyRequest(callbacks: IAuthCallbacks, request: ProxyRequest) { + Log.d(TAG, "performProxyRequest($packageName, $request)") + lifecycleScope.launchWhenStarted { + callbacks.onProxyResponse(ProxyResponse().apply { gmsStatusCode = CommonStatusCodes.CANCELED }) + } + } + + override fun getSpatulaHeader(callbacks: IAuthCallbacks) { + Log.d(TAG, "getSpatulaHeader($packageName)") + lifecycleScope.launchWhenStarted { + val result = withContext(Dispatchers.IO) { AppCertManager(context).getSpatulaHeader(packageName) } + Log.d(TAG, "Result: $result") + callbacks.onSpatulaHeader(result) + } + } + + override fun getLifecycle(): Lifecycle = lifecycle + + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) } +}