diff options
author | Fabian Henneke <FabianHenneke@users.noreply.github.com> | 2020-07-02 13:49:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-02 13:49:32 +0200 |
commit | ca9c951a536e9ccd2bf3e8f0e2e0a48992d0d655 (patch) | |
tree | bcf32f9bf6178051632baed95d5c70d8355f8e29 | |
parent | c702d4aa9ea09ae27e613d85440a207b37995e86 (diff) |
Fill OTP fields with SMS codes (#900)
* Fill OTP fields with SMS codes
* Allow SMS OTP fill also for web origins
* Introduce free and nonFree build variants
* Fix up workflow
* Improve layout and feature detection
* Workflow changes
* Add Changelog entry
* github: update release workflow for nonFree/Free split
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
* Switch to lifecycleScope
* github: make snapshot deploy free variant
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
-rw-r--r-- | .github/workflows/deploy_snapshot.yml | 2 | ||||
-rw-r--r-- | .github/workflows/pull_request.yml | 2 | ||||
-rw-r--r-- | .github/workflows/release.yml | 62 | ||||
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | app/build.gradle | 11 | ||||
-rw-r--r-- | app/src/free/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt | 28 | ||||
-rw-r--r-- | app/src/main/AndroidManifest.xml | 5 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt | 9 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillScenario.kt | 7 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/autofill/oreo/Form.kt | 13 | ||||
-rw-r--r-- | app/src/main/res/drawable/ic_autofill_sms.xml | 10 | ||||
-rw-r--r-- | app/src/main/res/layout/activity_oreo_autofill_sms.xml | 61 | ||||
-rw-r--r-- | app/src/main/res/values/strings.xml | 2 | ||||
-rw-r--r-- | app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt | 136 | ||||
-rw-r--r-- | dependencies.gradle | 4 | ||||
-rwxr-xr-x | release/deploy-snapshot.sh | 2 |
16 files changed, 330 insertions, 25 deletions
diff --git a/.github/workflows/deploy_snapshot.yml b/.github/workflows/deploy_snapshot.yml index e34e41bf..5b3b1cc4 100644 --- a/.github/workflows/deploy_snapshot.yml +++ b/.github/workflows/deploy_snapshot.yml @@ -51,7 +51,7 @@ jobs: run: ./gradlew dependencies - name: Build release app - run: ./gradlew :app:assembleRelease + run: ./gradlew :app:assembleFreeRelease env: SNAPSHOT: "true" diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index ccd77e8b..d4326bb0 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: api-level: [23, 29] - variant: [Debug, Release] + variant: [freeDebug, freeRelease, nonFreeRelease] steps: - name: Check if relevant files have changed diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b652347..5f03c588 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,20 +50,26 @@ jobs: - name: Download gradle dependencies run: ./gradlew dependencies - - name: Build release APK and bundle - run: ./gradlew :app:assembleRelease :app:bundleRelease + - name: Build release binaries + run: ./gradlew :app:assembleFreeRelease :app:assembleNonFreeRelease :app:bundleNonFreeRelease - - name: Upload release APK + - name: Upload non-free release APK uses: actions/upload-artifact@master with: - name: APS Release APK - path: app/build/outputs/apk/release/app-release.apk + name: APS Non-Free Release APK + path: app/build/outputs/apk/nonFree/release/app-release.apk - - name: Upload release Bundle + - name: Upload non-free release Bundle uses: actions/upload-artifact@master with: - name: APS Release Bundle - path: app/build/outputs/bundle/release/app-release.aab + name: APS Non-Free Release Bundle + path: app/build/outputs/bundle/nonFree/release/app-release.aab + + - name: Upload free release APK + uses: actions/upload-artifact@master + with: + name: APS Free Release APK + path: app/build/outputs/apk/free/release/app-release.apk - name: Clean secrets if: always() @@ -77,17 +83,23 @@ jobs: - name: Checkout uses: actions/checkout@v1 - - name: Get APK + - name: Get Non-Free Release APK uses: actions/download-artifact@v1 with: - name: APS Release APK - path: artifacts + name: APS Non-Free Release APK + path: artifacts/nonFree - - name: Get Bundle + - name: Get Non-Free Bundle uses: actions/download-artifact@v1 with: - name: APS Release Bundle - path: artifacts + name: APS Non-Free Release Bundle + path: artifacts/nonFree + + - name: Get Free Release APK + uses: actions/download-artifact@v1 + with: + name: APS Free Release APK + path: artifacts/free - name: Get Changelog Entry id: changelog_reader @@ -112,22 +124,32 @@ jobs: id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/} - - name: Upload Release Apk + - name: Upload Non-Free Release Apk uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./artifacts/app-release.apk - asset_name: APS_${{ steps.get_version.outputs.VERSION }}.apk + asset_path: ./artifacts/nonFree/app-release.apk + asset_name: APS-nonFree_${{ steps.get_version.outputs.VERSION }}.apk asset_content_type: application/vnd.android.package-archive - - name: Upload Release Bundle + - name: Upload Non-Free Release Bundle uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./artifacts/app-release.aab - asset_name: APS_${{ steps.get_version.outputs.VERSION }}.aab + asset_path: ./artifacts/nonFree/app-release.aab + asset_name: APS-nonFree_${{ steps.get_version.outputs.VERSION }}.aab asset_content_type: application/octet-stream + + - name: Upload Free Release Apk + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./artifacts/free/app-release.apk + asset_name: APS-free_${{ steps.get_version.outputs.VERSION }}.apk + asset_content_type: application/vnd.android.package-archive diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bc258b6..06b60282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - TOTP support is reintroduced by popular demand. HOTP continues to be unsupported and heavily discouraged. - Initial support for detecting and filling OTP fields with Autofill +- OTP codes can be automatically filled from SMS (requires Android P+ and Google Play Services) - Importing TOTP secrets using QR codes - Navigate into newly created folders and scroll to newly created passwords diff --git a/app/build.gradle b/app/build.gradle index 4489c0ba..399402cb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -68,6 +68,15 @@ android { buildTypes.release.signingConfig = signingConfigs.release buildTypes.debug.signingConfig = signingConfigs.release } + + flavorDimensions "free" + productFlavors { + free { + versionNameSuffix "-free" + } + nonFree { + } + } } dependencies { @@ -117,6 +126,8 @@ dependencies { debugImplementation deps.third_party.whatthestack } + nonFreeImplementation deps.non_free.google_play_auth_api_phone + // Testing-only dependencies androidTestImplementation deps.testing.junit androidTestImplementation deps.testing.kotlin_test_junit diff --git a/app/src/free/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt b/app/src/free/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt new file mode 100644 index 00000000..f86e5d4c --- /dev/null +++ b/app/src/free/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt @@ -0,0 +1,28 @@ +/* + * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ +package com.zeapo.pwdstore.autofill.oreo.ui + +import android.content.Context +import android.content.IntentSender +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import com.zeapo.pwdstore.autofill.oreo.FormOrigin + +@RequiresApi(Build.VERSION_CODES.O) +@Suppress("UNUSED_PARAMETER") +class AutofillSmsActivity : AppCompatActivity() { + + companion object { + + fun shouldOfferFillFromSms(context: Context): Boolean { + return false + } + + fun makeFillOtpFromSmsIntentSender(context: Context): IntentSender { + throw NotImplementedError("Filling OTPs from SMS requires non-free dependencies") + } + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2098abc9..40bcb481 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -139,6 +139,11 @@ android:name=".autofill.oreo.ui.AutofillSaveActivity" android:theme="@style/NoBackgroundTheme" /> <activity + android:name=".autofill.oreo.ui.AutofillSmsActivity" + android:configChanges="orientation" + android:theme="@style/DialogLikeTheme" + android:windowSoftInputMode="adjustNothing" /> + <activity android:name=".autofill.oreo.ui.AutofillPublisherChangedActivity" android:configChanges="orientation|keyboardHidden" android:theme="@style/DialogLikeTheme" diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt index 838b7a05..e9b2c630 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillHelper.kt @@ -87,7 +87,7 @@ val AssistStructure.ViewNode.webOrigin: String? "$scheme://$domain" } -data class Credentials(val username: String?, val password: String, val otp: String?) { +data class Credentials(val username: String?, val password: String?, val otp: String?) { companion object { fun fromStoreEntry( context: Context, @@ -141,6 +141,13 @@ fun makeGenerateAndFillRemoteView(context: Context, formOrigin: FormOrigin): Rem return makeRemoteView(context, title, summary, iconRes) } +fun makeFillOtpFromSmsRemoteView(context: Context, formOrigin: FormOrigin): RemoteViews { + val title = formOrigin.getPrettyIdentifier(context, untrusted = true) + val summary = context.getString(R.string.oreo_autofill_fill_otp_from_sms) + val iconRes = R.drawable.ic_autofill_sms + return makeRemoteView(context, title, summary, iconRes) +} + fun makePlaceholderRemoteView(context: Context): RemoteViews { return makeRemoteView(context, "PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher) } diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillScenario.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillScenario.kt index 8e209a60..ee8e3602 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillScenario.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillScenario.kt @@ -14,7 +14,7 @@ import androidx.annotation.RequiresApi import com.github.ajalt.timberkt.e enum class AutofillAction { - Match, Search, Generate + Match, Search, Generate, FillOtpFromSms } /** @@ -112,8 +112,13 @@ sealed class AutofillScenario<out T : Any> { AutofillAction.Match -> passwordFieldsToFillOnMatch + listOfNotNull(otp) AutofillAction.Search -> passwordFieldsToFillOnSearch + listOfNotNull(otp) AutofillAction.Generate -> passwordFieldsToFillOnGenerate + AutofillAction.FillOtpFromSms -> listOfNotNull(otp) } return when { + action == AutofillAction.FillOtpFromSms -> { + // When filling from an SMS, we cannot get any data other than the OTP itself. + credentialFieldsToFill + } credentialFieldsToFill.isNotEmpty() -> { // If the current action would fill into any password field, we also fill into the // username field if possible. diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/Form.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/Form.kt index 210fefab..e4ae1f75 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/Form.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/Form.kt @@ -25,6 +25,7 @@ import com.zeapo.pwdstore.autofill.oreo.ui.AutofillDecryptActivity import com.zeapo.pwdstore.autofill.oreo.ui.AutofillFilterView import com.zeapo.pwdstore.autofill.oreo.ui.AutofillPublisherChangedActivity import com.zeapo.pwdstore.autofill.oreo.ui.AutofillSaveActivity +import com.zeapo.pwdstore.autofill.oreo.ui.AutofillSmsActivity import java.io.File /** @@ -285,6 +286,14 @@ class FillableForm private constructor( return makePlaceholderDataset(remoteView, intentSender, AutofillAction.Generate) } + private fun makeFillOtpFromSmsDataset(context: Context): Dataset? { + if (scenario.fieldsToFillOn(AutofillAction.FillOtpFromSms).isEmpty()) return null + if (!AutofillSmsActivity.shouldOfferFillFromSms(context)) return null + val remoteView = makeFillOtpFromSmsRemoteView(context, formOrigin) + val intentSender = AutofillSmsActivity.makeFillOtpFromSmsIntentSender(context) + return makePlaceholderDataset(remoteView, intentSender, AutofillAction.FillOtpFromSms) + } + private fun makePublisherChangedDataset( context: Context, publisherChangedException: AutofillPublisherChangedException @@ -341,6 +350,10 @@ class FillableForm private constructor( hasDataset = true addDataset(it) } + makeFillOtpFromSmsDataset(context)?.let { + hasDataset = true + addDataset(it) + } if (!hasDataset) return null makeSaveInfo()?.let { setSaveInfo(it) } setClientState(clientState) diff --git a/app/src/main/res/drawable/ic_autofill_sms.xml b/app/src/main/res/drawable/ic_autofill_sms.xml new file mode 100644 index 00000000..e58c33c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_autofill_sms.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM9,11L7,11L7,9h2v2zM13,11h-2L11,9h2v2zM17,11h-2L15,9h2v2z" /> +</vector> diff --git a/app/src/main/res/layout/activity_oreo_autofill_sms.xml b/app/src/main/res/layout/activity_oreo_autofill_sms.xml new file mode 100644 index 00000000..608727d0 --- /dev/null +++ b/app/src/main/res/layout/activity_oreo_autofill_sms.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + ~ SPDX-License-Identifier: GPL-3.0-only + --> + +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingHorizontal="10dp" + tools:context="com.zeapo.pwdstore.autofill.oreo.ui.AutofillFilterView"> + + <ImageView + android:id="@+id/cover" + android:layout_width="0dp" + android:layout_height="50dp" + android:contentDescription="@string/app_name" + android:src="@drawable/ic_launcher_foreground" + app:layout_constraintBottom_toTopOf="@id/text" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:layout_margin="10dp" + app:layout_constraintVertical_bias="0.0" /> + + <TextView + android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/oreo_autofill_waiting_for_sms" + android:layout_margin="10dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/cover" /> + + <ProgressBar + android:id="@+id/progress" + style="@style/Widget.MaterialComponents.ProgressIndicator.Circular.Indeterminate" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="10dp" + app:layout_constraintBottom_toTopOf="@id/cancelButton" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/text" /> + + <Button + android:id="@+id/cancelButton" + style="@style/Widget.MaterialComponents.Button.TextButton" + android:layout_margin="10dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dialog_cancel" + android:textColor="?attr/colorSecondary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/progress" /> + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3023d995..6d06a7a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -253,6 +253,8 @@ <string name="oreo_autofill_save_app_not_supported">This app is currently not supported</string> <string name="oreo_autofill_save_passwords_dont_match">Passwords don\'t match</string> <string name="oreo_autofill_generate_password">Generate password…</string> + <string name="oreo_autofill_fill_otp_from_sms">Extract code from SMS…</string> + <string name="oreo_autofill_waiting_for_sms">Waiting for SMS…</string> <string name="oreo_autofill_max_matches_reached">Maximum number of matches (%1$d) reached; clear matches before adding new ones.</string> <string name="oreo_autofill_warning_publisher_header">This app\'s publisher has changed since you first associated a Password Store entry with it:</string> <string name="oreo_autofill_warning_publisher_footer"><b>The currently installed app may be trying to steal your credentials by pretending to be a trusted app.</b>\n\nTry to uninstall and reinstall the app from a trusted source, such as the Play Store, Amazon Appstore, F-Droid, or your phone manufacturer\'s store.</string> diff --git a/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt b/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt new file mode 100644 index 00000000..02394867 --- /dev/null +++ b/app/src/nonFree/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSmsActivity.kt @@ -0,0 +1,136 @@ +/* + * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ +package com.zeapo.pwdstore.autofill.oreo.ui + +import android.app.Activity +import android.app.PendingIntent +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.IntentSender +import android.os.Build +import android.os.Bundle +import android.view.autofill.AutofillManager +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import com.github.ajalt.timberkt.e +import com.github.ajalt.timberkt.w +import com.google.android.gms.auth.api.phone.SmsCodeRetriever +import com.google.android.gms.auth.api.phone.SmsRetriever +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability +import com.google.android.gms.common.api.ResolvableApiException +import com.google.android.gms.tasks.Tasks +import com.zeapo.pwdstore.autofill.oreo.AutofillAction +import com.zeapo.pwdstore.autofill.oreo.Credentials +import com.zeapo.pwdstore.autofill.oreo.FillableForm +import com.zeapo.pwdstore.databinding.ActivityOreoAutofillSmsBinding +import com.zeapo.pwdstore.utils.viewBinding +import kotlinx.coroutines.launch + +@RequiresApi(Build.VERSION_CODES.O) +class AutofillSmsActivity : AppCompatActivity() { + + companion object { + + private var fillOtpFromSmsRequestCode = 1 + + fun shouldOfferFillFromSms(context: Context): Boolean { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) + return false + val googleApiAvailabilityInstance = GoogleApiAvailability.getInstance() + val googleApiStatus = googleApiAvailabilityInstance.isGooglePlayServicesAvailable(context) + if (googleApiStatus != ConnectionResult.SUCCESS) { + w { "Google Play Services unavailable or not updated: ${googleApiAvailabilityInstance.getErrorString(googleApiStatus)}" } + return false + } + // https://developer.android.com/guide/topics/text/autofill-services#sms-autofill + if (googleApiAvailabilityInstance.getApkVersion(context) < 190056000) { + w { "Google Play Service 19.0.56 or higher required for SMS OTP Autofill" } + return false + } + return true + } + + fun makeFillOtpFromSmsIntentSender(context: Context): IntentSender { + val intent = Intent(context, AutofillSmsActivity::class.java) + return PendingIntent.getActivity( + context, + fillOtpFromSmsRequestCode++, + intent, + PendingIntent.FLAG_CANCEL_CURRENT + ).intentSender + } + } + + private val binding by viewBinding(ActivityOreoAutofillSmsBinding::inflate) + + private lateinit var clientState: Bundle + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + setResult(RESULT_CANCELED) + binding.cancelButton.setOnClickListener { + finish() + } + } + + override fun onStart() { + super.onStart() + clientState = intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE) ?: run { + e { "AutofillSmsActivity started without EXTRA_CLIENT_STATE" } + finish() + return + } + + registerReceiver(smsCodeRetrievedReceiver, IntentFilter(SmsCodeRetriever.SMS_CODE_RETRIEVED_ACTION), SmsRetriever.SEND_PERMISSION, null) + lifecycleScope.launch { + waitForSms() + } + } + + // Retry starting the SMS code retriever after a permission request. + @Suppress("DEPRECATION") + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode != Activity.RESULT_OK) + return + lifecycleScope.launch { + waitForSms() + } + } + + private fun waitForSms() { + val smsClient = SmsCodeRetriever.getAutofillClient(this@AutofillSmsActivity) + try { + Tasks.await(smsClient.startSmsCodeRetriever()) + } catch (e: ResolvableApiException) { + e.startResolutionForResult(this, 1) + } catch (e: Exception) { + e(e) + finish() + } + } + + private val smsCodeRetrievedReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val smsCode = intent.getStringExtra(SmsCodeRetriever.EXTRA_SMS_CODE) + val fillInDataset = + FillableForm.makeFillInDataset( + this@AutofillSmsActivity, + Credentials(null, null, smsCode), + clientState, + AutofillAction.FillOtpFromSms + ) + setResult(RESULT_OK, Intent().apply { + putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) + }) + finish() + } + } +} diff --git a/dependencies.gradle b/dependencies.gradle index f5c7c965..d05e0e6d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -64,6 +64,10 @@ ext.deps = [ whatthestack: 'com.github.haroldadmin:WhatTheStack:0.0.3', ], + non_free: [ + google_play_auth_api_phone: 'com.google.android.gms:play-services-auth-api-phone:17.4.0', + ], + testing: [ junit: 'junit:junit:4.13', kotlin_test_junit: 'org.jetbrains.kotlin:kotlin-test-junit:1.3.72', diff --git a/release/deploy-snapshot.sh b/release/deploy-snapshot.sh index 9139614b..3687ea46 100755 --- a/release/deploy-snapshot.sh +++ b/release/deploy-snapshot.sh @@ -5,7 +5,7 @@ mkdir -p "$SSHDIR" echo "$ACTIONS_DEPLOY_KEY" > "$SSHDIR/key" chmod 600 "$SSHDIR/key" export SERVER_DEPLOY_STRING="$SSH_USERNAME@$SERVER_ADDRESS:$SERVER_DESTINATION" -cd "$GITHUB_WORKSPACE/app/build/outputs/apk/release" +cd "$GITHUB_WORKSPACE/app/build/outputs/apk/free/release" rm output.json rsync -ahvcr --omit-dir-times --progress --delete --no-o --no-g -e "ssh -i $SSHDIR/key -o StrictHostKeyChecking=no -p $SSH_PORT" . "$SERVER_DEPLOY_STRING" || exit 1 exit 0 |