kotlin cleanup

This commit is contained in:
Milos Kozak 2020-03-20 18:13:07 +01:00
parent 5c04780de1
commit 4abc53e7b8
7 changed files with 162 additions and 176 deletions

View file

@ -6,8 +6,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.OneTimePassword import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.utils.OneTimePasswordValidationResult import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject import javax.inject.Inject
@ -21,7 +21,7 @@ class AuthRequest internal constructor(
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var otp :OneTimePassword @Inject lateinit var otp : OneTimePassword
private val date = DateUtil.now() private val date = DateUtil.now()
private var processed = false private var processed = false
@ -32,10 +32,10 @@ class AuthRequest internal constructor(
} }
private fun codeIsValid(toValidate: String) : Boolean { private fun codeIsValid(toValidate: String) : Boolean {
if (otp.isEnabled()) { return if (otp.isEnabled()) {
return otp.checkOTP(toValidate) == OneTimePasswordValidationResult.OK otp.checkOTP(toValidate) == OneTimePasswordValidationResult.OK
} else { } else {
return confirmCode.equals(toValidate) confirmCode == toValidate
} }
} }

View file

@ -28,6 +28,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin

View file

@ -8,21 +8,21 @@ import android.text.TextWatcher
import android.view.View import android.view.View
import com.google.common.primitives.Ints.min import com.google.common.primitives.Ints.min
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import dagger.android.DaggerActivity
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
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.FabricPrivacy
import info.nightscout.androidaps.utils.OKDialog import info.nightscout.androidaps.utils.OKDialog
import info.nightscout.androidaps.utils.OneTimePassword
import info.nightscout.androidaps.utils.OneTimePasswordValidationResult
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.activity_smscommunicator_otp.* import kotlinx.android.synthetic.main.activity_smscommunicator_otp.*
import net.glxn.qrgen.android.QRCode import net.glxn.qrgen.android.QRCode
import javax.inject.Inject import javax.inject.Inject
class SmsCommunicatorOtpActivity : DaggerActivity() { class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@ -35,27 +35,21 @@ class SmsCommunicatorOtpActivity : DaggerActivity() {
smscommunicator_otp_verify_edit.addTextChangedListener(object : TextWatcher { smscommunicator_otp_verify_edit.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) { override fun afterTextChanged(s: Editable) {
if (s != null) { val checkResult = otp.checkOTP(s.toString())
val checkResult = otp.checkOTP(s.toString())
smscommunicator_otp_verify_label.text = when (checkResult) { smscommunicator_otp_verify_label.text = when (checkResult) {
OneTimePasswordValidationResult.OK -> "OK" OneTimePasswordValidationResult.OK -> "OK"
OneTimePasswordValidationResult.ERROR_WRONG_LENGTH -> "INVALID SIZE!" OneTimePasswordValidationResult.ERROR_WRONG_LENGTH -> "INVALID SIZE!"
OneTimePasswordValidationResult.ERROR_WRONG_PIN -> "WRONG PIN" OneTimePasswordValidationResult.ERROR_WRONG_PIN -> "WRONG PIN"
OneTimePasswordValidationResult.ERROR_WRONG_OTP -> "WRONG OTP" OneTimePasswordValidationResult.ERROR_WRONG_OTP -> "WRONG OTP"
}
smscommunicator_otp_verify_label.setTextColor(when (checkResult) {
OneTimePasswordValidationResult.OK -> Color.GREEN
OneTimePasswordValidationResult.ERROR_WRONG_LENGTH -> Color.YELLOW
OneTimePasswordValidationResult.ERROR_WRONG_PIN -> Color.RED
OneTimePasswordValidationResult.ERROR_WRONG_OTP -> Color.RED
})
} else {
smscommunicator_otp_verify_label.text = "EMPTY";
smscommunicator_otp_verify_label.setTextColor(Color.YELLOW)
} }
smscommunicator_otp_verify_label.setTextColor(when (checkResult) {
OneTimePasswordValidationResult.OK -> Color.GREEN
OneTimePasswordValidationResult.ERROR_WRONG_LENGTH -> Color.YELLOW
OneTimePasswordValidationResult.ERROR_WRONG_PIN -> Color.RED
OneTimePasswordValidationResult.ERROR_WRONG_OTP -> Color.RED
})
} }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
@ -82,13 +76,13 @@ class SmsCommunicatorOtpActivity : DaggerActivity() {
} }
fun updateGui() { fun updateGui() {
val displayMetrics = Resources.getSystem().getDisplayMetrics() val displayMetrics = Resources.getSystem().displayMetrics
val width = displayMetrics.widthPixels val width = displayMetrics.widthPixels
val height = displayMetrics.heightPixels val height = displayMetrics.heightPixels
// ensure QRCode is big enough to fit on screen // ensure QRCode is big enough to fit on screen
val dim = (min(width, height) * 0.85).toInt() val dim = (min(width, height) * 0.85).toInt()
val provURI = otp.provisioningURI(); val provURI = otp.provisioningURI()
if (provURI != null) { if (provURI != null) {
val myBitmap = QRCode.from(provURI).withErrorCorrection(ErrorCorrectionLevel.H).withSize(dim, dim).bitmap() val myBitmap = QRCode.from(provURI).withErrorCorrection(ErrorCorrectionLevel.H).withSize(dim, dim).bitmap()

View file

@ -1,13 +1,13 @@
package info.nightscout.androidaps.utils package info.nightscout.androidaps.plugins.general.smsCommunicator.otp
import android.util.Base64 import android.util.Base64
import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator
import com.google.common.io.BaseEncoding import com.google.common.io.BaseEncoding
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.joda.time.DateTimeUtils
import java.net.URLEncoder import java.net.URLEncoder
import javax.crypto.KeyGenerator import javax.crypto.KeyGenerator
import javax.crypto.SecretKey import javax.crypto.SecretKey
@ -32,6 +32,7 @@ class OneTimePassword @Inject constructor(
companion object { companion object {
private lateinit var instance: OneTimePassword private lateinit var instance: OneTimePassword
@JvmStatic @JvmStatic
fun getInstance(): OneTimePassword = instance fun getInstance(): OneTimePassword = instance
} }
@ -40,7 +41,7 @@ class OneTimePassword @Inject constructor(
* If OTP Authenticator support is enabled by user * If OTP Authenticator support is enabled by user
*/ */
fun isEnabled(): Boolean { fun isEnabled(): Boolean {
return sp.getBoolean(R.string.key_smscommunicator_otp_enabled, true); return sp.getBoolean(R.string.key_smscommunicator_otp_enabled, true)
} }
/** /**
@ -49,7 +50,7 @@ class OneTimePassword @Inject constructor(
fun name(): String { fun name(): String {
val defaultUserName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name) val defaultUserName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name)
var userName = sp.getString(R.string.key_smscommunicator_otp_name, defaultUserName).replace(":", "").trim() var userName = sp.getString(R.string.key_smscommunicator_otp_name, defaultUserName).replace(":", "").trim()
if (userName.length == 0) if (userName.isEmpty())
userName = defaultUserName userName = defaultUserName
return userName return userName
} }
@ -58,16 +59,16 @@ class OneTimePassword @Inject constructor(
* Make sure if private key for TOTP is generated, creating it when necessary or requested * Make sure if private key for TOTP is generated, creating it when necessary or requested
*/ */
fun ensureKey(forceNewKey: Boolean = false) { fun ensureKey(forceNewKey: Boolean = false) {
var keyBytes: ByteArray = byteArrayOf() val keyBytes: ByteArray
val strSecret = sp.getString(R.string.key_smscommunicator_otp_secret, "").trim() val strSecret = sp.getString(R.string.key_smscommunicator_otp_secret, "").trim()
if (strSecret.length == 0 || forceNewKey) { if (strSecret.isEmpty() || forceNewKey) {
val keyGenerator = KeyGenerator.getInstance(totp.getAlgorithm()); val keyGenerator = KeyGenerator.getInstance(totp.algorithm)
keyGenerator.init(Constants.OTP_GENERATED_KEY_LENGTH_BITS); keyGenerator.init(Constants.OTP_GENERATED_KEY_LENGTH_BITS)
val generatedKey = keyGenerator.generateKey(); val generatedKey = keyGenerator.generateKey()
keyBytes = generatedKey.encoded keyBytes = generatedKey.encoded
sp.putString(R.string.key_smscommunicator_otp_secret, Base64.encodeToString(keyBytes, Base64.NO_WRAP + Base64.NO_PADDING)) sp.putString(R.string.key_smscommunicator_otp_secret, Base64.encodeToString(keyBytes, Base64.NO_WRAP + Base64.NO_PADDING))
} else { } else {
keyBytes = Base64.decode(strSecret, Base64.DEFAULT); keyBytes = Base64.decode(strSecret, Base64.DEFAULT)
} }
key = SecretKeySpec(keyBytes, 0, keyBytes.size, "SHA1") key = SecretKeySpec(keyBytes, 0, keyBytes.size, "SHA1")
} }
@ -77,13 +78,8 @@ class OneTimePassword @Inject constructor(
pin = sp.getString(R.string.key_smscommunicator_otp_password, "").trim() pin = sp.getString(R.string.key_smscommunicator_otp_password, "").trim()
} }
private fun generateOneTimePassword(counter: Long): String { private fun generateOneTimePassword(counter: Long): String =
if (key != null) { key?.let { String.format("%06d", totp.generateOneTimePassword(key, counter)) } ?: ""
return String.format("%06d", totp.generateOneTimePassword(key, counter))
} else {
return ""
}
}
/** /**
* Check if given OTP+PIN is valid * Check if given OTP+PIN is valid
@ -100,20 +96,19 @@ class OneTimePassword @Inject constructor(
return OneTimePasswordValidationResult.ERROR_WRONG_LENGTH return OneTimePasswordValidationResult.ERROR_WRONG_LENGTH
} }
if (!normalisedOtp.substring(6).equals(pin)) { if (normalisedOtp.substring(6) != pin) {
return OneTimePasswordValidationResult.ERROR_WRONG_PIN return OneTimePasswordValidationResult.ERROR_WRONG_PIN
} }
val milis: Long = DateTimeUtils.currentTimeMillis() val counter: Long = DateUtil.now() / 30000L
val counter: Long = (milis / 30000L)
var acceptableTokens: MutableList<String> = mutableListOf(generateOneTimePassword(counter)) val acceptableTokens: MutableList<String> = mutableListOf(generateOneTimePassword(counter))
for (i in 0 until Constants.OTP_ACCEPT_OLD_TOKENS_COUNT) { for (i in 0 until Constants.OTP_ACCEPT_OLD_TOKENS_COUNT) {
acceptableTokens.add(generateOneTimePassword(counter - i - 1)) acceptableTokens.add(generateOneTimePassword(counter - i - 1))
} }
val candidateOtp = normalisedOtp.substring(0, 6) val candidateOtp = normalisedOtp.substring(0, 6)
if (acceptableTokens.any { candidate -> candidateOtp.equals(candidate) }) { if (acceptableTokens.any { candidate -> candidateOtp == candidate }) {
return OneTimePasswordValidationResult.OK return OneTimePasswordValidationResult.OK
} }
@ -123,13 +118,7 @@ class OneTimePassword @Inject constructor(
/** /**
* Return URI used to provision Authenticator apps * Return URI used to provision Authenticator apps
*/ */
fun provisioningURI(): String? { fun provisioningURI(): String? =
val keyImm = key key?.let { "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8") + "?secret=" + BaseEncoding.base32().encode(it.encoded).replace("=", "") + "&issuer=AndroidAPS" }
if (keyImm != null) {
return "otpauth://totp/AndroidAPS:" + URLEncoder.encode(name(), "utf-8") + "?secret=" + BaseEncoding.base32().encode(keyImm.encoded).replace("=", "") + "&issuer=AndroidAPS"
} else {
return null
}
}
} }

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils package info.nightscout.androidaps.plugins.general.smsCommunicator.otp
enum class OneTimePasswordValidationResult { enum class OneTimePasswordValidationResult {
OK, OK,

View file

@ -2,10 +2,11 @@ package info.nightscout.androidaps.plugins.general.smsCommunicator
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -22,12 +23,13 @@ import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest(SmsCommunicatorPlugin::class, DateUtil::class) @PrepareForTest(SmsCommunicatorPlugin::class, DateUtil::class, OneTimePassword::class)
class AuthRequestTest : TestBase() { class AuthRequestTest : TestBase() {
@Mock lateinit var aapsLogger: AAPSLogger @Mock lateinit var aapsLogger: AAPSLogger
@Mock lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin @Mock lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var resourceHelper: ResourceHelper
@Mock lateinit var otp: OneTimePassword
var injector: HasAndroidInjector = HasAndroidInjector { var injector: HasAndroidInjector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
@ -35,6 +37,7 @@ class AuthRequestTest : TestBase() {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.resourceHelper = resourceHelper it.resourceHelper = resourceHelper
it.smsCommunicatorPlugin = smsCommunicatorPlugin it.smsCommunicatorPlugin = smsCommunicatorPlugin
it.otp = otp
} }
} }
} }

View file

@ -4,7 +4,6 @@ import android.telephony.SmsManager
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
@ -15,9 +14,9 @@ import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin