Skip to content

Commit

Permalink
improve NFC reading UX on android openpassport-org#130
Browse files Browse the repository at this point in the history
  • Loading branch information
BernalHQ committed Aug 7, 2024
1 parent 0c3d115 commit 0fbed19
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
import com.facebook.react.bridge.LifecycleEventListener
import com.facebook.react.bridge.Callback

object Messages {
const val SCANNING = "Scanning....."
const val STOP_MOVING = "Stop moving....."
const val AUTH = "Auth....."
const val COMPARING = "Comparing....."
const val COMPLETED = "Scanning completed"
const val RESET = ""
}

class Response(json: String) : JSONObject(json) {
val type: String? = this.optString("type")
val data = this.optJSONArray("data")
Expand Down Expand Up @@ -171,6 +180,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)

@ReactMethod
fun scan(opts: ReadableMap, promise: Promise) {
eventMessageEmitter(Messages.SCANNING)
val mNfcAdapter = NfcAdapter.getDefaultAdapter(reactApplicationContext)
// val mNfcAdapter = NfcAdapter.getDefaultAdapter(this.reactContext)
if (mNfcAdapter == null) {
Expand Down Expand Up @@ -261,6 +271,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)

override fun doInBackground(vararg params: Void?): Exception? {
try {
eventMessageEmitter(Messages.STOP_MOVING)
isoDep.timeout = 10000
Log.e("MY_LOGS", "This should obvsly log")
val cardService = CardService.getInstance(isoDep)
Expand Down Expand Up @@ -349,7 +360,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// e.printStackTrace()
// }
// Log.d(TAG, "============LET'S VERIFY THE SIGNATURE=============")

eventMessageEmitter(Messages.AUTH)
doChipAuth(service)
doPassiveAuth()

Expand All @@ -372,6 +383,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
imageBase64 = Base64.encodeToString(buffer, Base64.DEFAULT)
}
} catch (e: Exception) {
eventMessageEmitter(Messages.RESET)
return e
}
return null
Expand Down Expand Up @@ -409,8 +421,11 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)

val dataHashes = sodFile.dataGroupHashes

eventMessageEmitter("Reading DG14.....")
val dg14Hash = if (chipAuthSucceeded) digest.digest(dg14Encoded) else ByteArray(0)
eventMessageEmitter("Reading DG1.....")
val dg1Hash = digest.digest(dg1File.encoded)
eventMessageEmitter("Reading DG2.....")
val dg2Hash = digest.digest(dg2File.encoded)

// val gson = Gson()
Expand All @@ -432,7 +447,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
// Log.d(TAG, "dg2HashjoinToString " + gson.toJson(dg2Hash.joinToString("") { "%02x".format(it) }))

Log.d(TAG, "Comparing data group hashes...")

eventMessageEmitter(Messages.COMPARING)
if (Arrays.equals(dg1Hash, dataHashes[1]) && Arrays.equals(dg2Hash, dataHashes[2])
&& (!chipAuthSucceeded || Arrays.equals(dg14Hash, dataHashes[14]))) {

Expand Down Expand Up @@ -498,6 +513,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
Log.d(TAG, "Passive authentication success: $passiveAuthSuccess")
}
} catch (e: Exception) {
eventMessageEmitter(Messages.RESET)
Log.w(TAG, "Exception in passive authentication", e)
}
}
Expand Down Expand Up @@ -538,6 +554,7 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
val certificateBytes = certificate.encoded
val certificateBase64 = Base64.encodeToString(certificateBytes, Base64.DEFAULT)
Log.d(TAG, "certificateBase64: ${certificateBase64}")


passport.putString("documentSigningCertificate", certificateBase64)

Expand Down Expand Up @@ -609,7 +626,9 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
passport.putMap("photo", photo)
// passport.putString("dg2File", gson.toJson(dg2File))

eventMessageEmitter(Messages.COMPLETED)
scanPromise?.resolve(passport)
eventMessageEmitter(Messages.RESET)
resetState()
}
}
Expand All @@ -626,6 +645,16 @@ class RNPassportReaderModule(private val reactContext: ReactApplicationContext)
}
}

private fun eventMessageEmitter(message: String) {
if (reactContext.hasActiveCatalystInstance()) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit("NativeEvent", message)
} else {
Log.d(TAG, "Error")
}
}

companion object {
private val TAG = RNPassportReaderModule::class.java.simpleName
private const val PARAM_DOC_NUM = "documentNumber";
Expand Down
26 changes: 23 additions & 3 deletions app/src/screens/MainScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { YStack, XStack, Text, Button, Tabs, Sheet, Label, Fieldset, Input, Switch, H2, Image, useWindowDimensions, H4, H3 } from 'tamagui'
import { YStack, XStack, Text, Button, Tabs, Sheet, Label, Fieldset, Input, Switch, H2, Image, useWindowDimensions, H4, H3, View } from 'tamagui'
import { HelpCircle, IterationCw, VenetianMask, Cog, CheckCircle2, ChevronLeft, Share, Eraser } from '@tamagui/lucide-icons';
import X from '../images/x.png'
import Telegram from '../images/telegram.png'
Expand All @@ -8,7 +8,7 @@ import Internet from "../images/internet.png"
import ProveScreen from './ProveScreen';
import { Steps } from '../utils/utils';
import AppScreen from './AppScreen';
import { Linking, Modal, Platform, Pressable } from 'react-native';
import { NativeEventEmitter, NativeModules, Linking, Modal, Platform, Pressable } from 'react-native';
import NFC_IMAGE from '../images/nfc.png'
import { bgColor, blueColorLight, borderColor, componentBgColor, textColor1, textColor2 } from '../utils/colors';
import SendProofScreen from './SendProofScreen';
Expand All @@ -26,9 +26,12 @@ import Dialog from "react-native-dialog";
import { contribute } from '../utils/contribute';
import RegisterScreen from './RegisterScreen';

const { nativeModule } = NativeModules;
const emitter = new NativeEventEmitter(nativeModule);

const MainScreen: React.FC = () => {
const [NFCScanIsOpen, setNFCScanIsOpen] = useState(false);
const [scanningMessage, setScanningMessage] = useState('');
const [displayOtherOptions, setDisplayOtherOptions] = useState(false);
const [SettingsIsOpen, setSettingsIsOpen] = useState(false);
const [DialogContributeIsOpen, setDialogContributeIsOpen] = useState(false);
Expand Down Expand Up @@ -123,6 +126,18 @@ const MainScreen: React.FC = () => {
setDialogDeleteSecretIsOpen(false);
}

useEffect(() => {
const handleNativeEvent = (event: string) => {
setScanningMessage(event);
};

const subscription = emitter.addListener('NativeEvent', handleNativeEvent);

return () => {
subscription.remove();
};
}, []);

useEffect(() => {
if (passportNumber?.length === 9 && (dateOfBirth?.length === 6 && dateOfExpiry?.length === 6)) {
setStep(Steps.MRZ_SCAN_COMPLETED);
Expand Down Expand Up @@ -207,8 +222,13 @@ const MainScreen: React.FC = () => {
<Sheet open={NFCScanIsOpen} onOpenChange={setNFCScanIsOpen} dismissOnSnapToBottom modal dismissOnOverlayPress={false} disableDrag animation="medium" snapPoints={[35]}>
<Sheet.Overlay />
<Sheet.Frame>

<YStack gap="$5" f={1} pt="$3">
<H2 textAlign='center'>Ready to scan</H2>
<View>
<H2 textAlign='center'>Ready to scan</H2>
<Text textAlign='center'>{scanningMessage}</Text>
</View>

{step >= Steps.NEXT_SCREEN ?
<CheckCircle2
size="$8"
Expand Down
2 changes: 1 addition & 1 deletion app/src/utils/nfcScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ const handleResponseAndroid = async (
encapContent,
documentSigningCertificate
} = response;

amplitude.track('Sig alg before conversion: ' + signatureAlgorithm);

const pem = "-----BEGIN CERTIFICATE-----" + documentSigningCertificate + "-----END CERTIFICATE-----"
Expand Down

0 comments on commit 0fbed19

Please sign in to comment.