Estonian-ID-card-mobile-aut.../MobileAuthApp/app/src/main/java/com/tarkvaraprojekt/mobileauthapp/AuthFragment.kt

160 lines
6.3 KiB
Kotlin
Raw Normal View History

package com.tarkvaraprojekt.mobileauthapp
2021-11-08 22:41:09 +02:00
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.nfc.NfcAdapter
2021-11-25 18:09:45 +02:00
import android.nfc.TagLostException
import android.nfc.tech.IsoDep
import android.os.Bundle
import android.os.CountDownTimer
2021-10-08 21:24:21 +03:00
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.tarkvaraprojekt.mobileauthapp.NFC.Comms
import com.tarkvaraprojekt.mobileauthapp.auth.Authenticator
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentAuthBinding
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
2021-10-08 20:09:36 +03:00
import java.lang.Exception
import kotlin.system.exitProcess
/**
* Fragment that asks the user to detect the ID card with mobile NFC chip.
* Currently contains a next button that won't be needed later on.
* This button is just needed to test navigation between fragments so that every step exists.
*/
class AuthFragment : Fragment() {
private val viewModel: SmartCardViewModel by activityViewModels()
private val paramsModel: ParametersViewModel by activityViewModels()
2021-12-04 17:21:07 +02:00
private var _binding: FragmentAuthBinding? = null
private val binding get() = _binding!!
private val args: CanFragmentArgs by navArgs()
private lateinit var timer: CountDownTimer
private var timeRemaining: Int = 90
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
2021-12-04 17:21:07 +02:00
_binding = FragmentAuthBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
2021-10-08 20:09:36 +03:00
timer = object : CountDownTimer((timeRemaining * 1000).toLong(), 1000) {
override fun onTick(p0: Long) {
timeRemaining--
2021-10-08 20:09:36 +03:00
if (timeRemaining == 0) {
2021-12-04 17:21:07 +02:00
binding.timeCounter.text = getString(R.string.no_time)
2021-10-08 20:09:36 +03:00
} else {
2021-12-04 17:21:07 +02:00
binding.timeCounter.text = getString(R.string.time_left, timeRemaining)
2021-10-08 20:09:36 +03:00
}
}
override fun onFinish() {
2021-10-08 20:09:36 +03:00
Thread.sleep(750)
cancelAuth(408)
}
}.start()
// The button exists in code for testing reasons, but not visible to the user anymore unless visibility is changed in the code.
2021-12-04 17:21:07 +02:00
binding.nextButton.visibility = View.GONE
binding.nextButton.setOnClickListener { goToNextFragment() }
binding.cancelButton.setOnClickListener { cancelAuth(444) }
val adapter = NfcAdapter.getDefaultAdapter(activity)
if (adapter != null)
getInfoFromIdCard(adapter)
else { // If NFC adapter can not be detected then end the auth process as it is not possible to read an ID card
cancelAuth(447) // It would be a good idea to show user some notification as it might be confusing if the app suddenly closes
2021-11-25 18:09:45 +02:00
}
}
private fun goToNextFragment() {
timer.cancel()
val action = AuthFragmentDirections.actionAuthFragmentToResultFragment(mobile = args.mobile)
findNavController().navigate(action)
}
private fun cancelAuth(code: Int) {
2021-11-25 18:09:45 +02:00
viewModel.clearUserInfo()
timer.cancel()
if (args.mobile) {
val resultIntent = Intent()
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
requireActivity().finish()
} else {
(activity as MainActivity).returnError(code)
2021-11-25 18:09:45 +02:00
requireActivity().finishAndRemoveTask()
}
}
private fun getInfoFromIdCard(adapter: NfcAdapter) {
2021-11-08 22:41:09 +02:00
adapter.enableReaderMode(activity, { tag ->
timer.cancel()
requireActivity().runOnUiThread {
2021-12-04 17:21:07 +02:00
binding.timeCounter.text = getString(R.string.card_detected)
2021-11-08 22:41:09 +02:00
}
val card = IsoDep.get(tag)
card.timeout = 32768
card.use {
try {
val comms = Comms(it, viewModel.userCan)
2021-11-25 18:09:45 +02:00
val jws = Authenticator(comms).authenticate(
paramsModel.challenge,
paramsModel.origin,
2021-11-25 18:09:45 +02:00
viewModel.userPin
)
paramsModel.setToken(jws)
2021-11-08 23:17:36 +02:00
requireActivity().runOnUiThread {
2021-11-25 18:09:45 +02:00
goToNextFragment()
}
2021-11-08 22:41:09 +02:00
} catch (e: Exception) {
2021-11-25 18:09:45 +02:00
when(e) {
is TagLostException -> requireActivity().runOnUiThread {
binding!!.timeCounter.text = getString(R.string.id_card_removed_early)
cancelAuth(444)
}
2021-11-25 18:09:45 +02:00
else -> {
when ("invalid pin") {
in e.message.toString().lowercase() -> requireActivity().runOnUiThread {
val messagePieces = e.message.toString().split(" ")
2021-12-04 17:21:07 +02:00
binding.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1])
2021-11-25 18:09:45 +02:00
viewModel.deletePin(requireContext())
cancelAuth(449)
2021-11-25 18:09:45 +02:00
}
else -> requireActivity().runOnUiThread {
2021-12-04 17:21:07 +02:00
binding.timeCounter.text = getString(R.string.wrong_can_text)
2021-11-25 18:09:45 +02:00
viewModel.deleteCan(requireContext())
cancelAuth(449)
2021-11-25 18:09:45 +02:00
}
}
}
2021-11-08 22:41:09 +02:00
}
2021-11-25 18:09:45 +02:00
// Give user some time to read the error message
Thread.sleep(2000)
2021-11-08 22:41:09 +02:00
} finally {
adapter.disableReaderMode(activity)
}
2021-11-08 22:41:09 +02:00
}
}, NfcAdapter.FLAG_READER_NFC_A, null)
}
override fun onDestroy() {
super.onDestroy()
2021-12-04 17:21:07 +02:00
_binding = null
}
}