mirror of
https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC.git
synced 2024-12-22 20:40:16 +02:00
commit
aaa8d8f13c
@ -16,8 +16,10 @@ import androidx.navigation.fragment.findNavController
|
|||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import com.tarkvaraprojekt.mobileauthapp.NFC.Comms
|
import com.tarkvaraprojekt.mobileauthapp.NFC.Comms
|
||||||
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentAuthBinding
|
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentAuthBinding
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
|
||||||
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment that asks the user to detect the ID card with mobile NFC chip.
|
* Fragment that asks the user to detect the ID card with mobile NFC chip.
|
||||||
@ -28,6 +30,8 @@ class AuthFragment : Fragment() {
|
|||||||
|
|
||||||
private val viewModel: SmartCardViewModel by activityViewModels()
|
private val viewModel: SmartCardViewModel by activityViewModels()
|
||||||
|
|
||||||
|
private val intentParameters: ParametersViewModel by activityViewModels()
|
||||||
|
|
||||||
private var binding: FragmentAuthBinding? = null
|
private var binding: FragmentAuthBinding? = null
|
||||||
|
|
||||||
private val args: CanFragmentArgs by navArgs()
|
private val args: CanFragmentArgs by navArgs()
|
||||||
@ -51,9 +55,9 @@ class AuthFragment : Fragment() {
|
|||||||
override fun onTick(p0: Long) {
|
override fun onTick(p0: Long) {
|
||||||
timeRemaining--
|
timeRemaining--
|
||||||
if (timeRemaining == 0) {
|
if (timeRemaining == 0) {
|
||||||
binding!!.timeCounter.text = getString(R.string.no_time)
|
binding?.timeCounter?.text = getString(R.string.no_time)
|
||||||
} else {
|
} else {
|
||||||
binding!!.timeCounter.text = getString(R.string.time_left, timeRemaining)
|
binding?.timeCounter?.text = getString(R.string.time_left, timeRemaining)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,12 +129,18 @@ class AuthFragment : Fragment() {
|
|||||||
timer.cancel()
|
timer.cancel()
|
||||||
if (args.reading) {
|
if (args.reading) {
|
||||||
findNavController().navigate(R.id.action_authFragment_to_homeFragment)
|
findNavController().navigate(R.id.action_authFragment_to_homeFragment)
|
||||||
|
} else {
|
||||||
|
if (!args.mobile) {
|
||||||
|
//Currently for some reason the activity is not killed entirely. Must be looked into further.
|
||||||
|
requireActivity().finish()
|
||||||
|
exitProcess(0)
|
||||||
} else {
|
} else {
|
||||||
val resultIntent = Intent()
|
val resultIntent = Intent()
|
||||||
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
@ -6,11 +6,14 @@ import android.util.Log
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentHomeBinding
|
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentHomeBinding
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
|
||||||
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HomeFragment is only shown to the user when then the user launches the application. When the application
|
* HomeFragment is only shown to the user when then the user launches the application. When the application
|
||||||
@ -23,6 +26,8 @@ class HomeFragment : Fragment() {
|
|||||||
|
|
||||||
private val viewModel: SmartCardViewModel by activityViewModels()
|
private val viewModel: SmartCardViewModel by activityViewModels()
|
||||||
|
|
||||||
|
private val intentParams: ParametersViewModel by activityViewModels()
|
||||||
|
|
||||||
private var binding: FragmentHomeBinding? = null
|
private var binding: FragmentHomeBinding? = null
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@ -39,12 +44,30 @@ class HomeFragment : Fragment() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
initialChecks()
|
initialChecks()
|
||||||
var mobile = false
|
var auth = false
|
||||||
if (requireActivity().intent.data?.getQueryParameter("arg1") != null) {
|
if (requireActivity().intent.data?.getQueryParameter("action") != null) {
|
||||||
mobile = true
|
// Currently we only support authentication not signing.
|
||||||
|
auth = true
|
||||||
}
|
}
|
||||||
val auth = requireActivity().intent.getBooleanExtra("auth", false)
|
val mobile = requireActivity().intent.getBooleanExtra("mobile", false)
|
||||||
if (auth || mobile){
|
if (auth || mobile){
|
||||||
|
try {
|
||||||
|
if (mobile) {
|
||||||
|
// We use !! because we want an exception when something is not right.
|
||||||
|
intentParams.setChallenge(requireActivity().intent.getStringExtra("challenge")!!)
|
||||||
|
intentParams.setAuthUrl(requireActivity().intent.getStringExtra("authUrl")!!)
|
||||||
|
} else { //Website
|
||||||
|
// Currently the test website won't send the authUrl parameter
|
||||||
|
//Log.i("intentDebugging", requireActivity().intent.data.toString())
|
||||||
|
intentParams.setChallenge(requireActivity().intent.data!!.getQueryParameter("challenge")!!)
|
||||||
|
//intentParams.setAuthUrl(requireActivity().intent.data!!.getQueryParameter("authUrl")!!)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// There was a problem with parameters, which means that authentication is not possible.
|
||||||
|
val resultIntent = Intent()
|
||||||
|
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
goToTheNextFragment(true, mobile)
|
goToTheNextFragment(true, mobile)
|
||||||
}
|
}
|
||||||
binding!!.beginButton.setOnClickListener { goToTheNextFragment() }
|
binding!!.beginButton.setOnClickListener { goToTheNextFragment() }
|
||||||
|
@ -30,7 +30,7 @@ class PinFragment : Fragment() {
|
|||||||
// saving = true means that the user must be returned to the settings menu
|
// saving = true means that the user must be returned to the settings menu
|
||||||
// reading = true means that we are reading information from the ID card that does
|
// reading = true means that we are reading information from the ID card that does
|
||||||
// not require PIN 1 so it is not necessary to ask it.
|
// not require PIN 1 so it is not necessary to ask it.
|
||||||
private val args: CanFragmentArgs by navArgs()
|
private val args: PinFragmentArgs by navArgs()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -11,7 +11,14 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentResultBinding
|
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentResultBinding
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
|
||||||
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.network.TokenApi
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.network.TokenItem
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ResultFragment is used to create a JWT and to send response to the website/application
|
* ResultFragment is used to create a JWT and to send response to the website/application
|
||||||
@ -20,11 +27,11 @@ import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
|
|||||||
*/
|
*/
|
||||||
class ResultFragment : Fragment() {
|
class ResultFragment : Fragment() {
|
||||||
|
|
||||||
private val viewModel: SmartCardViewModel by activityViewModels()
|
private val paramsModel: ParametersViewModel by activityViewModels()
|
||||||
|
|
||||||
private var binding: FragmentResultBinding? = null
|
private var binding: FragmentResultBinding? = null
|
||||||
|
|
||||||
private val args: CanFragmentArgs by navArgs()
|
private val args: ResultFragmentArgs by navArgs()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -38,15 +45,44 @@ class ResultFragment : Fragment() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding!!.resultBackButton.setOnClickListener {
|
binding!!.resultBackButton.setOnClickListener {
|
||||||
if (!args.mobile) {
|
if (args.mobile) {
|
||||||
createResponse()
|
createResponse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createResponse() {
|
/**
|
||||||
|
* Makes a POST request to the backend server with a tokenItem
|
||||||
|
*/
|
||||||
|
fun postToken() {
|
||||||
|
val tokenData = TokenItem(
|
||||||
|
paramsModel.token,
|
||||||
|
paramsModel.challenge
|
||||||
|
)
|
||||||
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
|
val response = TokenApi.retrofitService.postToken(tokenData)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
//Success scenario here
|
||||||
|
} else {
|
||||||
|
//Failure scenario here
|
||||||
|
if (args.mobile) {
|
||||||
|
createResponse(false)
|
||||||
|
} else {
|
||||||
|
//Currently for some reason the activity is not killed entirely. Must be looked into further.
|
||||||
|
requireActivity().finish()
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only used when the MobileAuthApp was launched by an app. Not for website use.
|
||||||
|
*/
|
||||||
|
private fun createResponse(success: Boolean = true) {
|
||||||
|
val responseCode = if (success) AppCompatActivity.RESULT_OK else AppCompatActivity.RESULT_CANCELED
|
||||||
val resultIntent = Intent()
|
val resultIntent = Intent()
|
||||||
requireActivity().setResult(AppCompatActivity.RESULT_OK, resultIntent)
|
requireActivity().setResult(responseCode, resultIntent)
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.tarkvaraprojekt.mobileauthapp.model
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class ParametersViewModel: ViewModel() {
|
||||||
|
|
||||||
|
private var _challenge: String = ""
|
||||||
|
val challenge get() = _challenge
|
||||||
|
|
||||||
|
private var _authUrl: String = ""
|
||||||
|
val authUrl get() = _authUrl
|
||||||
|
|
||||||
|
private var _token: String = ""
|
||||||
|
val token get() = _token
|
||||||
|
|
||||||
|
fun setChallenge(newChallenge: String) {
|
||||||
|
_challenge = newChallenge
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAuthUrl(newAuthUrl: String) {
|
||||||
|
_authUrl = newAuthUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setToken(newToken: String) {
|
||||||
|
_token = newToken
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
package com.tarkvaraprojekt.mobileauthapp.network
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Placeholder ResponseItem.
|
|
||||||
*/
|
|
||||||
data class ResponseItem (
|
|
||||||
val data1: Int,
|
|
||||||
val data2: Int,
|
|
||||||
)
|
|
@ -22,12 +22,9 @@ private val retrofit = Retrofit.Builder().addConverterFactory(MoshiConverterFact
|
|||||||
.baseUrl(BASE_URL).build()
|
.baseUrl(BASE_URL).build()
|
||||||
|
|
||||||
interface TokenApiService {
|
interface TokenApiService {
|
||||||
@GET("something")
|
|
||||||
suspend fun getData(): ResponseItem
|
|
||||||
|
|
||||||
@Headers("Content-Type: application/json")
|
@Headers("Content-Type: application/json")
|
||||||
@POST("posts")
|
@POST("auth/authentication")
|
||||||
suspend fun addData(@Body data: ResponseItem): Response<ResponseItem>
|
suspend fun postToken(@Body data: TokenItem): Response<TokenItem>
|
||||||
}
|
}
|
||||||
|
|
||||||
object TokenApi {
|
object TokenApi {
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.tarkvaraprojekt.mobileauthapp.network
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TokenItem for making POST request.
|
||||||
|
*/
|
||||||
|
data class TokenItem (
|
||||||
|
val token: String,
|
||||||
|
val challenge: String,
|
||||||
|
)
|
@ -35,17 +35,20 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.loginOptionNfcButton.setOnClickListener { launchAuth() }
|
binding.loginOptionNfcButton.setOnClickListener { launchAuth() }
|
||||||
|
//binding.loginOptionNfcButton.setOnClickListener { getData() }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method that creates an intent to launch the MobileAuthApp
|
* Method that creates an intent to launch the MobileAuthApp
|
||||||
*/
|
*/
|
||||||
private fun launchAuth(arg: String = "nothing") {
|
private fun launchAuth(challenge: String = "challenge", authUrl: String = "authUrl") {
|
||||||
val launchIntent = Intent()
|
val launchIntent = Intent()
|
||||||
launchIntent.setClassName("com.tarkvaraprojekt.mobileauthapp", "com.tarkvaraprojekt.mobileauthapp.MainActivity")
|
launchIntent.setClassName("com.tarkvaraprojekt.mobileauthapp", "com.tarkvaraprojekt.mobileauthapp.MainActivity")
|
||||||
launchIntent.putExtra("auth", true)
|
launchIntent.putExtra("action", "auth")
|
||||||
launchIntent.putExtra("nonce", arg) // Currently nothing
|
launchIntent.putExtra("challenge", challenge)
|
||||||
|
launchIntent.putExtra("authUrl", authUrl)
|
||||||
|
launchIntent.putExtra("mobile", true)
|
||||||
authLauncher.launch(launchIntent)
|
authLauncher.launch(launchIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,14 +57,17 @@ class MainActivity : AppCompatActivity() {
|
|||||||
* Ion library is used as it is very convenient for making simple GET requests.
|
* Ion library is used as it is very convenient for making simple GET requests.
|
||||||
*/
|
*/
|
||||||
private fun getData() {
|
private fun getData() {
|
||||||
val url = "real-address-here"
|
// Enter the server endpoint address to here
|
||||||
|
val baseUrl = "enter-base-url-here"
|
||||||
|
val url = "$baseUrl/auth/challenge"
|
||||||
Ion.with(applicationContext)
|
Ion.with(applicationContext)
|
||||||
.load(url)
|
.load(url)
|
||||||
.asJsonObject()
|
.asJsonObject()
|
||||||
.setCallback { _, result ->
|
.setCallback { _, result ->
|
||||||
try {
|
try {
|
||||||
// Get data from the result and call launchAuth method
|
// Get data from the result and call launchAuth method
|
||||||
launchAuth()
|
val challenge = result.asJsonObject["nonce"].toString()
|
||||||
|
launchAuth(challenge, baseUrl)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.i("GETrequest", "was unsuccessful")
|
Log.i("GETrequest", "was unsuccessful")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user