Create the methods to ask for the current Security Lock before showing the BrainKey.

master
Severiano Jaramillo 2019-02-14 13:41:27 -06:00
parent f3c85e8875
commit b4965d8a01
3 changed files with 80 additions and 41 deletions

View File

@ -16,15 +16,19 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
companion object {
/** Used to denote that the user is in the step of creating the preferred security lock option */
const val SECURITY_LOG_STEP_CREATE = 1
const val STEP_SECURITY_LOCK_CREATE = 1
/** Used to denote that the user is in the step of confirming the newly created security lock option */
private const val SECURITY_LOG_STEP_CONFIRM = 2
private const val STEP_SECURITY_LOCK_CONFIRM = 2
/** Used to denote that the user is in the step of verifying the current security lock option, to give
* permission to do a security constrained action like sending a transaction or trying to change the
* current security lock option */
const val SECURITY_LOG_STEP_VERIFY = 3
const val STEP_SECURITY_LOCK_VERIFY = 3
/** Used to let the dialog know if the user wants to create a new PIN/Pattern or just verify its correctness
* to get access to security constrained actions */
const val KEY_STEP_SECURITY_LOCK = "key_step_security_lock"
/** The calling fragment can be calling this dialog to unlock many different things, this variable helps to
* keep track of what action the calling fragment wants to achieve */
@ -40,6 +44,10 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
/** Callback used to notify the parent that a PIN/Pattern has been entered successfully */
protected var mCallback: OnPINPatternEnteredListener? = null
/** Keeps track of the current step, can be create, confirm of verify */
protected var currentStep: Int = 1
/** Used so the calling object knows what was the intention to ask for the Security Lock */
protected var actionIdentifier: Int = 0
/** Keeps track of all RxJava disposables, to make sure they are all disposed when the fragment is destroyed */
@ -56,6 +64,8 @@ abstract class BaseSecurityLockDialog : DialogFragment() {
currentEncryptedPINPattern = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_ENCRYPTED_PIN, "")?.trim()
currentStep = arguments?.getInt(KEY_STEP_SECURITY_LOCK) ?: 0
actionIdentifier = arguments?.getInt(KEY_ACTION_IDENTIFIER) ?: 0
}

View File

@ -33,12 +33,16 @@ class PINSecurityLockDialog : BaseSecurityLockDialog() {
var handled = false
if (actionId == EditorInfo.IME_ACTION_GO) {
val encryptedPIN = CryptoUtils.encrypt(v.context, v.text.toString()).trim()
if (encryptedPIN == currentEncryptedPINPattern) {
// PIN is correct, proceed
dismiss()
mCallback?.onPINPatternEntered(actionIdentifier)
} else {
tilPIN.error = "Wrong PIN"
if (currentStep == STEP_SECURITY_LOCK_VERIFY) {
// The user just wants to verify the current encrypted PIN/Pattern
if (encryptedPIN == currentEncryptedPINPattern) {
// PIN is correct, proceed
dismiss()
mCallback?.onPINPatternEntered(actionIdentifier)
} else {
tilPIN.error = "Wrong PIN"
}
}
handled = true

View File

@ -43,6 +43,7 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
private const val TAG = "SettingsFragment"
private const val ACTION_CHANGE_SECURITY_LOCK = 1
private const val ACTION_SHOW_BRAINKEY = 2
}
private var mDisposables = CompositeDisposable()
@ -74,8 +75,6 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
initNightModeSwitch()
btnViewBrainKey.setOnClickListener { getBrainkey(it) }
tvNetworkStatus.setOnClickListener { v ->
if (mNetworkService != null) {
// PublishSubject used to announce full node latencies updates
@ -109,6 +108,11 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
// 1 -> Pattern
// 2 -> None
btnViewBrainKey.setOnClickListener {
if (!verifySecurityLock(securityLockSelected, ACTION_SHOW_BRAINKEY))
getBrainkey()
}
tvSecurityLockSelected.text = resources.getStringArray(R.array.security_lock_options)[securityLockSelected]
tvSecurityLock.setOnClickListener { onSecurityLockTextSelected(securityLockSelected) }
@ -213,26 +217,46 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
}
private fun onSecurityLockTextSelected(securityLockSelected: Int) {
when (securityLockSelected) {
if (!verifySecurityLock(securityLockSelected, ACTION_CHANGE_SECURITY_LOCK))
showChooseSecurityLockDialog()
}
/**
* Encapsulated the logic required to do actions possibly locked by the Security Lock. If PIN/Pattern is selected
* then it prompts for it.
*
* @param securityLockSelected Current Security Lock option selected
* @param actionIdentifier Identifier used to know why a verify security lock was launched
* @return true if the action was handled, false otherwise
*/
private fun verifySecurityLock(securityLockSelected: Int, actionIdentifier: Int): Boolean {
return when (securityLockSelected) {
0 /* PIN */ -> {
val pinFrag = PINSecurityLockDialog()
val args = Bundle()
args.putInt(BaseSecurityLockDialog.KEY_ACTION_IDENTIFIER, ACTION_CHANGE_SECURITY_LOCK)
args.putInt(BaseSecurityLockDialog.KEY_STEP_SECURITY_LOCK,
BaseSecurityLockDialog.STEP_SECURITY_LOCK_VERIFY)
args.putInt(BaseSecurityLockDialog.KEY_ACTION_IDENTIFIER, actionIdentifier)
pinFrag.arguments = args
pinFrag.show(childFragmentManager, "pin_security_lock_tag")
true
}
1 /* Pattern */ -> {
true
}
else -> { /* None */
false
}
}
}
override fun onPINPatternEntered(actionIdentifier: Int) {
if (actionIdentifier == ACTION_CHANGE_SECURITY_LOCK)
if (actionIdentifier == ACTION_CHANGE_SECURITY_LOCK) {
showChooseSecurityLockDialog()
} else if (actionIdentifier == ACTION_SHOW_BRAINKEY) {
getBrainkey()
}
}
override fun onPINPatternChanged() {
@ -249,9 +273,6 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
listItems(R.array.security_lock_options) {dialog, index, text ->
dialog.context.toast("$text selected!")
}
cancelable(false)
cancelOnTouchOutside(false)
negativeButton(android.R.string.cancel)
}
}
}
@ -260,37 +281,41 @@ class SettingsFragment : Fragment(), ServiceConnection, BaseSecurityLockDialog.O
* Obtains the brainKey from the authorities db table for the current user account and if it is not null it passes
* the brainKey to a method to show it in a nice MaterialDialog
*/
private fun getBrainkey(view: View) {
val userId = PreferenceManager.getDefaultSharedPreferences(view.context)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
private fun getBrainkey() {
context?.let {
val userId = PreferenceManager.getDefaultSharedPreferences(it)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
val authorityRepository = AuthorityRepository(view.context)
val authorityRepository = AuthorityRepository(it)
mDisposables.add(authorityRepository.get(userId)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { authority ->
if (authority != null) {
val plainBrainKey = CryptoUtils.decrypt(view.context, authority.encryptedBrainKey)
val plainSequenceNumber = CryptoUtils.decrypt(view.context, authority.encryptedSequenceNumber)
val sequenceNumber = Integer.parseInt(plainSequenceNumber)
val brainKey = BrainKey(plainBrainKey, sequenceNumber)
showBrainKeyDialog(view, brainKey)
mDisposables.add(authorityRepository.get(userId)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { authority ->
if (authority != null) {
val plainBrainKey = CryptoUtils.decrypt(it, authority.encryptedBrainKey)
val plainSequenceNumber = CryptoUtils.decrypt(it, authority.encryptedSequenceNumber)
val sequenceNumber = Integer.parseInt(plainSequenceNumber)
val brainKey = BrainKey(plainBrainKey, sequenceNumber)
showBrainKeyDialog(brainKey)
}
}
}
)
)
}
}
/**
* Shows the plain brainkey in a dialog so that the user can view and Copy it.
*/
private fun showBrainKeyDialog(view: View, brainKey: BrainKey) {
MaterialDialog(view.context).show {
title(text = "BrainKey")
message(text = brainKey.brainKey)
customView(R.layout.dialog_copy_brainkey)
cancelable(false)
positiveButton(R.string.button__copied) { it.dismiss() }
private fun showBrainKeyDialog(brainKey: BrainKey) {
context?.let { context ->
MaterialDialog(context).show {
title(text = "BrainKey")
message(text = brainKey.brainKey)
customView(R.layout.dialog_copy_brainkey)
cancelable(false)
positiveButton(R.string.button__copied) { it.dismiss() }
}
}
}