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.LTag
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.OneTimePassword
import info.nightscout.androidaps.utils.OneTimePasswordValidationResult
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
@ -21,7 +21,7 @@ class AuthRequest internal constructor(
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var otp :OneTimePassword
@Inject lateinit var otp : OneTimePassword
private val date = DateUtil.now()
private var processed = false
@ -32,10 +32,10 @@ class AuthRequest internal constructor(
}
private fun codeIsValid(toValidate: String) : Boolean {
if (otp.isEnabled()) {
return otp.checkOTP(toValidate) == OneTimePasswordValidationResult.OK
return if (otp.isEnabled()) {
otp.checkOTP(toValidate) == OneTimePasswordValidationResult.OK
} 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.notifications.Notification
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.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin

View file

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

View file

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

View file

@ -1,8 +1,8 @@
package info.nightscout.androidaps.utils
enum class OneTimePasswordValidationResult {
OK,
ERROR_WRONG_LENGTH,
ERROR_WRONG_PIN,
ERROR_WRONG_OTP
package info.nightscout.androidaps.plugins.general.smsCommunicator.otp
enum class OneTimePasswordValidationResult {
OK,
ERROR_WRONG_LENGTH,
ERROR_WRONG_PIN,
ERROR_WRONG_OTP
}

View file

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

View file

@ -4,7 +4,6 @@ import android.telephony.SmsManager
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile
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.PluginType
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.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.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin