Skip to content

Commit

Permalink
Add the portrait to the whole passport registration pipeline
Browse files Browse the repository at this point in the history
Signed-off-by: GabrielFleicher <[email protected]>
  • Loading branch information
GabrielFleischer committed Jan 12, 2024
1 parent b638331 commit e8ce67f
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.epfl.dedis.hbt.data.user

import android.content.SharedPreferences
import com.epfl.dedis.hbt.data.Result
import com.epfl.dedis.hbt.data.document.Portrait
import com.epfl.dedis.hbt.service.document.DocumentService
import com.epfl.dedis.hbt.service.json.JsonService
import com.epfl.dedis.hbt.service.json.JsonType.USER_DATA
import javax.inject.Inject
Expand All @@ -13,7 +15,8 @@ import javax.inject.Singleton
@Singleton
class UserDataSource @Inject constructor(
private val sharedPref: SharedPreferences,
private val jsonService: JsonService
private val jsonService: JsonService,
private val documentService: DocumentService
) {

private val usernamesKey: String = "users"
Expand Down Expand Up @@ -47,11 +50,23 @@ class UserDataSource @Inject constructor(
return username == usernamesKey || users.containsKey(username)
}

fun register(username: String, pincode: Int, passport: String, role: Role): Result<User> {
fun register(
username: String,
pincode: Int,
passport: String,
role: Role,
portrait: Portrait
): Result<User> {
if (isRegistered(username)) return Result.Error(Exception("Already registered"))

// create user
val user = User(username, pincode, passport, role)
val call = documentService.create(user, portrait, false)
val response = call.execute()
if (response.errorBody() != null) {
return Result.Error(Exception("Failed to register : " + response.message()))
}

users[username] = user

//create wallet
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.epfl.dedis.hbt.data.user

import com.epfl.dedis.hbt.data.Result
import com.epfl.dedis.hbt.data.document.Portrait
import javax.inject.Inject
import javax.inject.Singleton

Expand Down Expand Up @@ -36,9 +37,15 @@ class UserRepository @Inject constructor(private val dataSource: UserDataSource)
loggedInUser = null
}

fun register(username: String, pincode: String, passport: String, role: Role): Result<User> {
fun register(
username: String,
pincode: String,
passport: String,
role: Role,
portrait: Portrait
): Result<User> {
val pin = pincode.toIntOrNull() ?: return Result.Error(NumberFormatException())
val result = dataSource.register(username, pin, passport, role)
val result = dataSource.register(username, pin, passport, role, portrait)

if (result is Result.Success) {
setLoggedInUser(result.data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.epfl.dedis.hbt.service.document

import com.epfl.dedis.hbt.data.document.Document
import com.epfl.dedis.hbt.data.document.Portrait
import com.epfl.dedis.hbt.data.user.User
import okhttp3.MediaType
import okhttp3.RequestBody
import retrofit2.Call
import retrofit2.http.Multipart
Expand All @@ -18,4 +21,13 @@ interface DocumentService {
@Part("image") image: RequestBody,
@Part("registered") registered: Boolean
): Call<Document>

fun create(user: User, portrait: Portrait, registered: Boolean): Call<Document> =
create(
user.name,
user.passport,
user.role.ordinal,
RequestBody.create(MediaType.parse(portrait.type), portrait.data),
registered
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.epfl.dedis.hbt.service.passport

import com.epfl.dedis.hbt.data.document.Portrait
import com.epfl.dedis.hbt.service.passport.mrz.MRZInfo
import org.jmrtd.lds.SODFile
import org.jmrtd.lds.icao.DG11File

data class Passport(
val mrzInfo: MRZInfo,
val sodFile: SODFile,
val portrait: Portrait,
val dg11File: DG11File?
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.util.Log
import com.epfl.dedis.hbt.data.Result
import com.epfl.dedis.hbt.data.Result.Error
import com.epfl.dedis.hbt.data.Result.Success
import com.epfl.dedis.hbt.data.document.Portrait
import com.epfl.dedis.hbt.service.passport.Passport
import com.epfl.dedis.hbt.service.passport.mrz.BACData
import com.epfl.dedis.hbt.service.passport.mrz.MRZInfo
Expand Down Expand Up @@ -45,10 +46,18 @@ object NFCReader {

val passportNFC = PassportNFC(ps, bacData)
Log.d("PASS_RESULT", passportNFC.dg1File?.mrzInfo.toString())

val portraitImage = passportNFC.dg5File!!.images.first()
val portrait = Portrait(
portraitImage.mimeType,
portraitImage.encoded
)

Success(
Passport(
MRZInfo(passportNFC.dg1File!!.mrzInfo),
passportNFC.sodFile!!,
portrait,
passportNFC.dg11File
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jmrtd.lds.*
import org.jmrtd.lds.icao.COMFile
import org.jmrtd.lds.icao.DG11File
import org.jmrtd.lds.icao.DG1File
import org.jmrtd.lds.icao.DG5File
import java.io.IOException
import java.security.GeneralSecurityException

Expand All @@ -31,6 +32,9 @@ constructor(service: PassportService, bacData: BACData) {
private set
var dg1File: DG1File? = null
private set
var dg5File: DG5File? = null
private set

var dg11File: DG11File? = null
private set

Expand Down Expand Up @@ -107,6 +111,7 @@ constructor(service: PassportService, bacData: BACData) {
try {
sodFile = service.getSodFile()
dg1File = service.getDG1File()
dg5File = service.getDG5File()
dg11File = service.getDG11File()
} catch (ioe: IOException) {
ioe.printStackTrace()
Expand Down Expand Up @@ -147,6 +152,10 @@ constructor(service: PassportService, bacData: BACData) {
private fun PassportService.getDG1File(): DG1File =
getFile(PassportService.EF_DG1)

@Throws(CardServiceException::class, IOException::class)
private fun PassportService.getDG5File(): DG5File =
getFile(PassportService.EF_DG5)

@Throws(CardServiceException::class, IOException::class)
private fun PassportService.getDG11File(): DG11File =
getFile(PassportService.EF_DG11)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ class NFCPassportFragment : Fragment() {
parentFragmentManager,
RegisterFragment.newInstance(
passport.mrzInfo.number,
personalData
personalData,
passport.portrait
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.epfl.dedis.hbt.R
import com.epfl.dedis.hbt.data.document.Portrait
import com.epfl.dedis.hbt.data.user.Role
import com.epfl.dedis.hbt.databinding.FragmentRegisterBinding
import com.epfl.dedis.hbt.ui.MainActivity
Expand All @@ -26,13 +27,18 @@ class RegisterFragment : Fragment() {

private const val PASSPORT = "PASSPORT"
private const val CHECKSUM = "CHECKSUM"

fun newInstance(passport: String, checksum: String) = RegisterFragment().apply {
val bundle = Bundle()
bundle.putString(PASSPORT, passport)
bundle.putString(CHECKSUM, checksum)
arguments = bundle
}
private const val PORTRAIT_TYPE = "PORTRAIT_TYPE"
private const val PORTRAIT_DATA = "PORTRAIT_DATA"

fun newInstance(passport: String, checksum: String, portrait: Portrait) =
RegisterFragment().apply {
val bundle = Bundle()
bundle.putString(PASSPORT, passport)
bundle.putString(CHECKSUM, checksum)
bundle.putString(PORTRAIT_TYPE, portrait.type)
bundle.putByteArray(PORTRAIT_DATA, portrait.data)
arguments = bundle
}
}

private val registerViewModel: RegisterViewModel by viewModels(ownerProducer = { requireActivity() })
Expand All @@ -44,6 +50,7 @@ class RegisterFragment : Fragment() {

private lateinit var passport: String
private lateinit var checksum: ByteArray
private lateinit var portrait: Portrait

override fun onCreateView(
inflater: LayoutInflater,
Expand All @@ -61,6 +68,10 @@ class RegisterFragment : Fragment() {
checksum = it.toByteArray()
passportChecksum.text = it
}

val portraitType = requireArguments().getString(PORTRAIT_TYPE)!!
val portraitData = requireArguments().getByteArray(PORTRAIT_DATA)!!
portrait = Portrait(portraitType, portraitData)
}

return binding.root
Expand Down Expand Up @@ -135,6 +146,7 @@ class RegisterFragment : Fragment() {
usernameEditText.text.toString(),
pincodeEditText.text.toString(),
passport,
portrait,
checksum,
role
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.epfl.dedis.hbt.R
import com.epfl.dedis.hbt.data.Result.Success
import com.epfl.dedis.hbt.data.document.Portrait
import com.epfl.dedis.hbt.data.user.Role
import com.epfl.dedis.hbt.data.user.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -24,11 +25,12 @@ class RegisterViewModel @Inject constructor(private val userRepository: UserRepo
username: String,
pincode: String,
passport: String,
portrait: Portrait,
checksum: ByteArray,
role: Role
) {
// can be launched in a separate asynchronous job
val result = userRepository.register(username, pincode, passport, role)
val result = userRepository.register(username, pincode, passport, role, portrait)

if (result is Success) {
_registerResult.value = RegisterResult(error = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@ package com.epfl.dedis.hbt.data

import androidx.test.espresso.matcher.ViewMatchers.assertThat
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.epfl.dedis.hbt.data.document.Document
import com.epfl.dedis.hbt.data.user.Role
import com.epfl.dedis.hbt.data.user.User
import com.epfl.dedis.hbt.data.user.UserDataSource
import com.epfl.dedis.hbt.di.JsonModule.provideObjectMapper
import com.epfl.dedis.hbt.service.document.DocumentService
import com.epfl.dedis.hbt.service.document.DocumentServiceTest
import com.epfl.dedis.hbt.service.json.JsonService
import com.epfl.dedis.hbt.test.MockSharedPreferences
import org.hamcrest.CoreMatchers.instanceOf
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import retrofit2.Call
import retrofit2.Response
import org.hamcrest.CoreMatchers.`is` as eq

/**
Expand All @@ -21,8 +29,18 @@ import org.hamcrest.CoreMatchers.`is` as eq
class UserDataSourceTest {

private val jsonService = JsonService(provideObjectMapper())
private val docService = mock<DocumentService> {
on { create(any(), any(), any(), any(), any()) } doReturn mockCall(Document("ID"))
}

private fun <T> mockCall(body: T): Call<T> = mock {
on { execute() } doReturn Response.success(body)
}

private val preferences = MockSharedPreferences()

private val mockPortrait = DocumentServiceTest.getMockPortrait()

private val alice = User("Alice", 12345, "XX4130X3")
private val bob = User("Bob", 67890, "54X62C3", Role.MERCHANT)

Expand All @@ -33,26 +51,29 @@ class UserDataSourceTest {

@Test
fun userDataSourceRegistrationTest() {
val dataSource = UserDataSource(preferences, jsonService)
val dataSource = UserDataSource(preferences, jsonService, docService)

assertThat(dataSource.login(alice.name, alice.pincode), instanceOf(Result.Error::class.java))
assertThat(
dataSource.login(alice.name, alice.pincode),
instanceOf(Result.Error::class.java)
)
assertThat(dataSource.login(bob.name, bob.pincode), instanceOf(Result.Error::class.java))

dataSource.register(alice.name, alice.pincode, alice.passport, alice.role)
dataSource.register(bob.name, bob.pincode, bob.passport, bob.role)
dataSource.register(alice.name, alice.pincode, alice.passport, alice.role, mockPortrait)
dataSource.register(bob.name, bob.pincode, bob.passport, bob.role, mockPortrait)

assertThat(dataSource.login(alice.name, alice.pincode), eq(Result.Success(alice)))
assertThat(dataSource.login(bob.name, bob.pincode), eq(Result.Success(bob)))
}

@Test
fun userDataSourceStoresUsers() {
val dataSource = UserDataSource(preferences, jsonService)
val dataSource = UserDataSource(preferences, jsonService, docService)

dataSource.register(alice.name, alice.pincode, alice.passport, alice.role)
dataSource.register(bob.name, bob.pincode, bob.passport, bob.role)
dataSource.register(alice.name, alice.pincode, alice.passport, alice.role, mockPortrait)
dataSource.register(bob.name, bob.pincode, bob.passport, bob.role, mockPortrait)

val dataSourceLoaded = UserDataSource(preferences, jsonService)
val dataSourceLoaded = UserDataSource(preferences, jsonService, docService)

assertThat(dataSourceLoaded.login(alice.name, alice.pincode), eq(Result.Success(alice)))
assertThat(dataSourceLoaded.login(bob.name, bob.pincode), eq(Result.Success(bob)))
Expand Down

0 comments on commit e8ce67f

Please sign in to comment.