Skip to content

Commit

Permalink
Fixed the NFC COVID certificate scanner (eu-digital-green-certificate…
Browse files Browse the repository at this point in the history
…s#237)

* Fixed the NFC COVID certificate scanner

* Onboarded Darko Jelen's fix of try/catching the code in onNdefMessageReceived(), to prevent the app from crashing if another NFC tag is read while the decoded screen of the previous certificate is still up on the screen.

* All the NDEF messages and all the records contained on an NFC tag are parsed, and those of type urn:nfc:wkt:T containing a text record starting with "HC1:" are decoded.
This allows a mixed usage of the NFC tag - for example formatted as a smart poster containing the bearer's information in plain text and a PNG image of the COVID certificate's QR code, readable by any cellphone without the verifier app, as well as the COVID certificate string that can be read and decoded by the verifier app natively.
Previously, the NFC tag had contain only a single message with a single urn:nfc:wkt:T text record containing the COVID certificate string, and was not usable in any other fashion.

Co-authored-by: Giraut <>
  • Loading branch information
Giraut committed Feb 2, 2022
1 parent bd1994c commit 400bbb4
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 28 deletions.
33 changes: 16 additions & 17 deletions app/src/main/java/dgca/verifier/app/android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,25 +113,24 @@ class MainActivity : AppCompatActivity() {
return
}

val builder = StringBuilder()
val records = NdefParser.parse(messages[0])
val size = records.size

for (i in 0 until size) {
val record = records[i]
val str = record.str()
builder.append(str)
}

val qrCodeText = builder.toString()
if (qrCodeText.isNotEmpty()) {
navHostFragment.childFragmentManager.primaryNavigationFragment?.let { fragment ->
if (fragment is CodeReaderFragment && fragment.isVisible) {
fragment.onNdefMessageReceived(qrCodeText)
val itr = messages.listIterator()

while (itr.hasNext()) {
val records = NdefParser.parse(itr.next())

for (i in 0 until records.size) {
if (records[i] != null) {
val record = records[i].str()

if (record.length >= 5 && record.substring(0, 4) == "HC1:") {
navHostFragment.childFragmentManager.primaryNavigationFragment?.let { fragment ->
if (fragment is CodeReaderFragment && fragment.isVisible) {
fragment.onNdefMessageReceived(record)
}
}
}
}
}
} else {
Timber.d("Received empty NDEFMessage")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ fun NdefRecord.parse(): ParsedNdefRecord? {
Charsets.UTF_16
}

val text = String(recordPayload, textEncoding)
val langCodeLen = (recordPayload[0] and 63.toByte()).toInt()
val text = String(recordPayload, textEncoding).substring(1 + langCodeLen)

return TextRecord(text)
} catch (e: UnsupportedEncodingException) {
Timber.w("We got a malformed tag.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,21 +267,15 @@ class CodeReaderFragment : BindingFragment<FragmentCodeReaderBinding>(), NavCont
}

fun onNdefMessageReceived(qrCodeText: String) {
val position = binding.countrySelector.selectedItemPosition
if (position == -1 || refinedCountries.isEmpty()) {
return
}

try {
val countryCode = refinedCountries[position].toLowerCase(Locale.ROOT)
val action =
CodeReaderFragmentDirections.actionCodeReaderFragmentToVerificationDialogFragment(
qrCodeText,
countryCode
qrCodeText,
binding.countrySelector.selectedItem?.toString() ?: ""
)
findNavController().navigate(action)
} catch (ex: Exception) {
Timber.d("Cannot get iso country code for position.")
Timber.d("action_codeReaderFragment_to_verificationDialogFragment cannot be found from the current destination Destination.")
}
}
}
}

0 comments on commit 400bbb4

Please sign in to comment.