160 lines
6.3 KiB
Kotlin
160 lines
6.3 KiB
Kotlin
package com.tarkvaraprojekt.mobileauthapp
|
|
|
|
import android.app.Activity
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.nfc.NfcAdapter
|
|
import android.nfc.TagLostException
|
|
import android.nfc.tech.IsoDep
|
|
import android.os.Bundle
|
|
import android.os.CountDownTimer
|
|
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
|
|
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()
|
|
|
|
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? {
|
|
_binding = FragmentAuthBinding.inflate(inflater, container, false)
|
|
return binding.root
|
|
}
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
super.onViewCreated(view, savedInstanceState)
|
|
timer = object : CountDownTimer((timeRemaining * 1000).toLong(), 1000) {
|
|
override fun onTick(p0: Long) {
|
|
timeRemaining--
|
|
if (timeRemaining == 0) {
|
|
binding.timeCounter.text = getString(R.string.no_time)
|
|
} else {
|
|
binding.timeCounter.text = getString(R.string.time_left, timeRemaining)
|
|
}
|
|
}
|
|
|
|
override fun onFinish() {
|
|
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.
|
|
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
|
|
}
|
|
}
|
|
|
|
private fun goToNextFragment() {
|
|
timer.cancel()
|
|
val action = AuthFragmentDirections.actionAuthFragmentToResultFragment(mobile = args.mobile)
|
|
findNavController().navigate(action)
|
|
}
|
|
|
|
private fun cancelAuth(code: Int) {
|
|
viewModel.clearUserInfo()
|
|
timer.cancel()
|
|
if (args.mobile) {
|
|
val resultIntent = Intent()
|
|
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
|
requireActivity().finish()
|
|
} else {
|
|
(activity as MainActivity).returnError(code)
|
|
requireActivity().finishAndRemoveTask()
|
|
}
|
|
}
|
|
|
|
private fun getInfoFromIdCard(adapter: NfcAdapter) {
|
|
adapter.enableReaderMode(activity, { tag ->
|
|
timer.cancel()
|
|
requireActivity().runOnUiThread {
|
|
binding.timeCounter.text = getString(R.string.card_detected)
|
|
}
|
|
val card = IsoDep.get(tag)
|
|
card.timeout = 32768
|
|
card.use {
|
|
try {
|
|
val comms = Comms(it, viewModel.userCan)
|
|
val jws = Authenticator(comms).authenticate(
|
|
paramsModel.challenge,
|
|
paramsModel.origin,
|
|
viewModel.userPin
|
|
)
|
|
paramsModel.setToken(jws)
|
|
requireActivity().runOnUiThread {
|
|
goToNextFragment()
|
|
}
|
|
} catch (e: Exception) {
|
|
when(e) {
|
|
is TagLostException -> requireActivity().runOnUiThread {
|
|
binding!!.timeCounter.text = getString(R.string.id_card_removed_early)
|
|
cancelAuth(444)
|
|
}
|
|
else -> {
|
|
when ("invalid pin") {
|
|
in e.message.toString().lowercase() -> requireActivity().runOnUiThread {
|
|
val messagePieces = e.message.toString().split(" ")
|
|
binding.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1])
|
|
viewModel.deletePin(requireContext())
|
|
cancelAuth(449)
|
|
}
|
|
else -> requireActivity().runOnUiThread {
|
|
binding.timeCounter.text = getString(R.string.wrong_can_text)
|
|
viewModel.deleteCan(requireContext())
|
|
cancelAuth(449)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Give user some time to read the error message
|
|
Thread.sleep(2000)
|
|
} finally {
|
|
adapter.disableReaderMode(activity)
|
|
}
|
|
}
|
|
}, NfcAdapter.FLAG_READER_NFC_A, null)
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
_binding = null
|
|
}
|
|
} |