Implemented catching Flickercode decoding errors and displaying them in UI
This commit is contained in:
parent
b3f815eb7e
commit
9869b44ccd
|
@ -26,7 +26,6 @@ import net.dankito.banking.ui.model.TanMediumStatus
|
||||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||||
import net.dankito.fints.model.*
|
import net.dankito.fints.model.*
|
||||||
import net.dankito.fints.response.client.FinTsClientResponse
|
import net.dankito.fints.response.client.FinTsClientResponse
|
||||||
import net.dankito.fints.tan.TanImage
|
|
||||||
|
|
||||||
|
|
||||||
open class EnterTanDialog : DialogFragment() {
|
open class EnterTanDialog : DialogFragment() {
|
||||||
|
@ -136,7 +135,14 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
if (tanChallenge is FlickercodeTanChallenge) {
|
if (tanChallenge is FlickercodeTanChallenge) {
|
||||||
val flickerCodeView = rootView.flickerCodeView
|
val flickerCodeView = rootView.flickerCodeView
|
||||||
flickerCodeView.visibility = View.VISIBLE
|
flickerCodeView.visibility = View.VISIBLE
|
||||||
flickerCodeView.setCode((tanChallenge as FlickercodeTanChallenge).flickercode)
|
|
||||||
|
val flickercode = (tanChallenge as FlickercodeTanChallenge).flickercode
|
||||||
|
if (flickercode.decodingSuccessful) {
|
||||||
|
flickerCodeView.setCode(flickercode)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showDecodingTanChallengeFailedErrorDelayed(flickercode.error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (tanChallenge is ImageTanChallenge) {
|
else if (tanChallenge is ImageTanChallenge) {
|
||||||
rootView.tanImageView.visibility = View.VISIBLE
|
rootView.tanImageView.visibility = View.VISIBLE
|
||||||
|
@ -147,7 +153,7 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
rootView.imgTanImageView.setImageBitmap(bitmap)
|
rootView.imgTanImageView.setImageBitmap(bitmap)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showDecodingTanImageFailedErrorDelayed(decodedImage) // this method gets called right on start up before dialog is shown -> Alert would get displayed before dialog and therefore covered by dialog if we don't delay displaying dialog
|
showDecodingTanChallengeFailedErrorDelayed(decodedImage.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,16 +162,20 @@ open class EnterTanDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected open fun showDecodingTanImageFailedErrorDelayed(decodedImage: TanImage) {
|
/**
|
||||||
|
* This method gets called right on start up before dialog is shown -> Alert would get displayed before dialog and
|
||||||
|
* therefore covered by dialog -> delay displaying alert.
|
||||||
|
*/
|
||||||
|
protected open fun showDecodingTanChallengeFailedErrorDelayed(error: Exception?) {
|
||||||
val handler = Handler()
|
val handler = Handler()
|
||||||
|
|
||||||
handler.postDelayed({ showDecodingTanImageFailedError(decodedImage) }, 500)
|
handler.postDelayed({ showDecodingTanChallengeFailedError(error) }, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun showDecodingTanImageFailedError(decodedImage: TanImage) {
|
protected open fun showDecodingTanChallengeFailedError(error: Exception?) {
|
||||||
activity?.let { context ->
|
activity?.let { context ->
|
||||||
AlertDialog.Builder(context)
|
AlertDialog.Builder(context)
|
||||||
.setMessage(context.getString(R.string.dialog_enter_tan_error_could_not_decode_tan_image, decodedImage.error?.localizedMessage))
|
.setMessage(context.getString(R.string.dialog_enter_tan_error_could_not_decode_tan_image, error?.localizedMessage))
|
||||||
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
|
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,20 @@ package net.dankito.fints.tan
|
||||||
|
|
||||||
open class Flickercode(
|
open class Flickercode(
|
||||||
val challengeHHD_UC: String,
|
val challengeHHD_UC: String,
|
||||||
val parsedDataSet: String
|
val parsedDataSet: String,
|
||||||
)
|
val error: Exception? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
val decodingSuccessful: Boolean
|
||||||
|
get() = error == null
|
||||||
|
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
if (decodingSuccessful == false) {
|
||||||
|
return "Decoding error: $error"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Parsed $challengeHHD_UC to $parsedDataSet"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package net.dankito.fints.tan
|
package net.dankito.fints.tan
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,36 +8,44 @@ open class FlickercodeDecoder {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ContainsOtherSymbolsThanFiguresPattern: Pattern = Pattern.compile("\\D")
|
val ContainsOtherSymbolsThanFiguresPattern: Pattern = Pattern.compile("\\D")
|
||||||
|
|
||||||
|
private val log = LoggerFactory.getLogger(FlickercodeDecoder::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun decodeChallenge(challengeHHD_UC: String): Flickercode {
|
open fun decodeChallenge(challengeHHD_UC: String): Flickercode {
|
||||||
val challengeLength = parseIntToHex(challengeHHD_UC.substring(0, 2))
|
try {
|
||||||
|
val challengeLength = parseIntToHex(challengeHHD_UC.substring(0, 2))
|
||||||
|
|
||||||
val startCode = parseStartCode(challengeHHD_UC, 2)
|
val startCode = parseStartCode(challengeHHD_UC, 2)
|
||||||
|
|
||||||
val controlByte = "" // TODO (there can be multiple of them!)
|
val controlByte = "" // TODO (there can be multiple of them!)
|
||||||
|
|
||||||
val de1 = parseDatenelement(challengeHHD_UC, startCode.endIndex)
|
val de1 = parseDatenelement(challengeHHD_UC, startCode.endIndex)
|
||||||
val de2 = parseDatenelement(challengeHHD_UC, de1.endIndex)
|
val de2 = parseDatenelement(challengeHHD_UC, de1.endIndex)
|
||||||
val de3 = parseDatenelement(challengeHHD_UC, de2.endIndex)
|
val de3 = parseDatenelement(challengeHHD_UC, de2.endIndex)
|
||||||
|
|
||||||
val luhnChecksum = calculateLuhnChecksum(startCode, controlByte, de1, de2, de3)
|
val luhnChecksum = calculateLuhnChecksum(startCode, controlByte, de1, de2, de3)
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// können im HHDUC-Protokoll Datenelemente ausgelassen werden, indem als Länge LDE1, LDE2 oder LDE3 = ‘00‘ angegeben wird.
|
// können im HHDUC-Protokoll Datenelemente ausgelassen werden, indem als Länge LDE1, LDE2 oder LDE3 = ‘00‘ angegeben wird.
|
||||||
// Dadurch wird gekennzeichnet, dass das jeweilige, durch den Start-Code definierte Datenelement nicht im HHDUC-Datenstrom
|
// Dadurch wird gekennzeichnet, dass das jeweilige, durch den Start-Code definierte Datenelement nicht im HHDUC-Datenstrom
|
||||||
// enthalten ist. Somit sind für leere Datenelemente die Längenfelder zu übertragen, wenn danach noch nicht-leere
|
// enthalten ist. Somit sind für leere Datenelemente die Längenfelder zu übertragen, wenn danach noch nicht-leere
|
||||||
// Datenelemente folgen. Leere Datenelemente am Ende des Datenstromes können komplett inklusive Längenfeld entfallen.
|
// Datenelemente folgen. Leere Datenelemente am Ende des Datenstromes können komplett inklusive Längenfeld entfallen.
|
||||||
val dataWithoutLengthAndChecksum = startCode.lengthInByte + controlByte + startCode + de1.lengthInByte + de1.data + de2.lengthInByte + de2.data + de3.lengthInByte + de3.data
|
val dataWithoutLengthAndChecksum = startCode.lengthInByte + controlByte + startCode + de1.lengthInByte + de1.data + de2.lengthInByte + de2.data + de3.lengthInByte + de3.data
|
||||||
val dataLength = (dataWithoutLengthAndChecksum.length + 2) / 2 // + 2 for checksum
|
val dataLength = (dataWithoutLengthAndChecksum.length + 2) / 2 // + 2 for checksum
|
||||||
val dataWithoutChecksum = toHex(dataLength, 2) + dataWithoutLengthAndChecksum
|
val dataWithoutChecksum = toHex(dataLength, 2) + dataWithoutLengthAndChecksum
|
||||||
|
|
||||||
val xorChecksumString = calculateXorChecksum(dataWithoutChecksum)
|
val xorChecksumString = calculateXorChecksum(dataWithoutChecksum)
|
||||||
|
|
||||||
val parsedDataSet = dataWithoutChecksum + luhnChecksum + xorChecksumString
|
val parsedDataSet = dataWithoutChecksum + luhnChecksum + xorChecksumString
|
||||||
|
|
||||||
return Flickercode(challengeHHD_UC, parsedDataSet)
|
return Flickercode(challengeHHD_UC, parsedDataSet)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error("Could not decode challenge $challengeHHD_UC")
|
||||||
|
|
||||||
|
return Flickercode(challengeHHD_UC, "", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun parseStartCode(challengeHHD_UC: String, startIndex: Int): FlickercodeDatenelement {
|
protected fun parseStartCode(challengeHHD_UC: String, startIndex: Int): FlickercodeDatenelement {
|
||||||
|
|
|
@ -12,6 +12,10 @@ open class TanImage(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
if (decodingSuccessful == false) {
|
||||||
|
return "Decoding error: $error"
|
||||||
|
}
|
||||||
|
|
||||||
return "$mimeType ${imageBytes.size} bytes"
|
return "$mimeType ${imageBytes.size} bytes"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue