From 0df3aaccae9c2c2bf8575cde91555335bb8f850a Mon Sep 17 00:00:00 2001 From: Dominik Dzienia Date: Thu, 22 Oct 2020 22:27:49 +0200 Subject: [PATCH 1/3] Secure authenticator QRCode against screen grabers --- .../smsCommunicator/activities/SmsCommunicatorOtpActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt index 964d87ab70..12e4679d38 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt @@ -6,6 +6,7 @@ import android.os.Bundle import android.text.Editable import android.text.TextWatcher import android.view.View +import android.view.WindowManager import com.google.common.primitives.Ints.min import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import info.nightscout.androidaps.R @@ -31,6 +32,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); setContentView(R.layout.activity_smscommunicator_otp) smscommunicator_otp_verify_edit.addTextChangedListener(object : TextWatcher { From b2bd2cafeca3efedea2fe0f127da44e8d38508ff Mon Sep 17 00:00:00 2001 From: Dominik Dzienia Date: Thu, 22 Oct 2020 23:18:52 +0200 Subject: [PATCH 2/3] Allow exporting OTP authenticator secred, for manual provisioning or use in hardware OTP token burning apps --- .../activities/SmsCommunicatorOtpActivity.kt | 21 +++++++++++++++++-- .../smsCommunicator/otp/OneTimePassword.kt | 6 ++++++ app/src/main/res/values/strings.xml | 4 ++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt index 12e4679d38..e1cdce7d17 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/activities/SmsCommunicatorOtpActivity.kt @@ -1,5 +1,8 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator.activities +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context import android.content.res.Resources import android.graphics.Color import android.os.Bundle @@ -16,8 +19,8 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicato import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.ToastUtils +import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.resources.ResourceHelper import kotlinx.android.synthetic.main.activity_smscommunicator_otp.* import net.glxn.qrgen.android.QRCode @@ -66,9 +69,23 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() { Runnable { otp.ensureKey(true) updateGui() - ToastUtils.showToastInUiThread(this, R.string.smscommunicator_otp_reset_successful) + ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_reset_successful)) }) } + + smscommunicator_otp_provisioning.setOnLongClickListener { + OKDialog.showConfirmation(this, + resourceHelper.gs(R.string.smscommunicator_otp_export_title), + resourceHelper.gs(R.string.smscommunicator_otp_export_prompt), + Runnable { + val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip = ClipData.newPlainText("OTP Secret", otp.provisioningSecret()) + clipboard.primaryClip = clip + ToastUtils.Long.infoToast(this, resourceHelper.gs(R.string.smscommunicator_otp_export_successful)) + }) + + true + } } @Synchronized diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt index 3610fb37b4..75b913c302 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/otp/OneTimePassword.kt @@ -121,4 +121,10 @@ class OneTimePassword @Inject constructor( fun provisioningURI(): String? = key?.let { "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8").replace("+", "%20") + "?secret=" + BaseEncoding.base32().encode(it.encoded).replace("=", "") + "&issuer=AndroidAPS" } + /** + * Return secret used to provision Authenticator apps, in Base32 format + */ + fun provisioningSecret(): String? = + key?.let { BaseEncoding.base32().encode(it.encoded).replace("=", "") } + } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 891c266dd0..e9dd459b02 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1376,6 +1376,10 @@ Are you sure to reset Authenticator key? It will render all currently configured Authenticators invalid, and you will need to set them up again. New Authenticator Key was generated! Please use updated QRCode to provision authenticators. + Exporting OTP secret + Are you sure you want to copy OTP secret to clipboard?\n\nYou may only need that if your authenticator app have issues scanning QRCode, you want to enter it manually or you want to configure hardware OTP token using dedicated app. + OTP secret (in Base32 format) exported and copied into clipboard. Paste it into authenticator or hardware OTP burner! + 1. Install Authenticator 2. Scan code to setup AndroidAPS OTP codes 3. Test One-Time-Password From 0f4a428c0046fde371d9aceab5acced1e52619bf Mon Sep 17 00:00:00 2001 From: Dominik Dzienia Date: Thu, 22 Oct 2020 23:49:36 +0200 Subject: [PATCH 3/3] Prevent duplicate numbers in SMS communicator config --- .../general/smsCommunicator/SmsCommunicatorPlugin.kt | 6 +++--- .../utils/textValidator/validators/MultiPhoneValidator.kt | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt index c64701ea73..9beccc7ccd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt @@ -1004,7 +1004,7 @@ class SmsCommunicatorPlugin @Inject constructor( private fun areMoreNumbers(allowednumbers: String?): Boolean { return allowednumbers?.let { - var countNumbers = 0 + val knownNumbers = HashSet() val substrings = it.split(";").toTypedArray() for (number in substrings) { var cleaned = number.replace(Regex("\\s+"), "") @@ -1012,9 +1012,9 @@ class SmsCommunicatorPlugin @Inject constructor( cleaned = cleaned.replace("+", "") cleaned = cleaned.replace("-", "") if (!cleaned.matches(Regex("[0-9]+"))) continue - countNumbers++ + knownNumbers.add(cleaned) } - countNumbers > 1 + knownNumbers.size > 1 } ?: false } } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/textValidator/validators/MultiPhoneValidator.kt b/core/src/main/java/info/nightscout/androidaps/utils/textValidator/validators/MultiPhoneValidator.kt index 3baba5240d..a2c6d8f882 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/textValidator/validators/MultiPhoneValidator.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/textValidator/validators/MultiPhoneValidator.kt @@ -7,9 +7,13 @@ class MultiPhoneValidator(val _customErrorMessage: String?) : Validator(_customE override fun isValid(editText: EditText): Boolean { val substrings = editText.text.split(";").toTypedArray() + val knownNumbers = HashSet() for (number in substrings) { if (!PatternValidator(_customErrorMessage, Patterns.PHONE).isValid(number)) return false + if (knownNumbers.contains(number)) + return false + knownNumbers.add(number) } return substrings.isNotEmpty() }