Implemented mapping all tan procedures returned from German banks: Merged photoTAN and PushTan with appTAN, added ChipTanUsb and ChipTanPhotoTanMatrixCode, renamed ChipTanOptisch to ChipTanFlickercode

This commit is contained in:
dankito 2020-04-30 17:16:55 +02:00
parent 4d50ded3fa
commit 95ce20b5bb
9 changed files with 80 additions and 32 deletions

View File

@ -7,13 +7,15 @@ enum class TanProcedureType {
ChipTanManuell,
ChipTanOptisch,
ChipTanFlickercode,
ChipTanUsb,
ChipTanQrCode,
PhotoTan,
ChipTanPhotoTanMatrixCode,
SmsTan,
PushTan
AppTan
}

View File

@ -29,7 +29,7 @@ import javax.inject.Inject
open class EnterTanDialog : DialogFragment() {
companion object {
val OpticalTanProcedures = listOf(TanProcedureType.ChipTanOptisch, TanProcedureType.ChipTanQrCode, TanProcedureType.PhotoTan)
val OpticalTanProcedures = listOf(TanProcedureType.ChipTanFlickercode, TanProcedureType.ChipTanQrCode, TanProcedureType.ChipTanPhotoTanMatrixCode)
const val DialogTag = "EnterTanDialog"
}

View File

@ -217,11 +217,12 @@ open class fints4javaModelMapper {
return when (type) {
net.dankito.fints.model.TanProcedureType.EnterTan -> TanProcedureType.EnterTan
net.dankito.fints.model.TanProcedureType.ChipTanManuell -> TanProcedureType.ChipTanManuell
net.dankito.fints.model.TanProcedureType.ChipTanOptisch -> TanProcedureType.ChipTanOptisch
net.dankito.fints.model.TanProcedureType.ChipTanFlickercode -> TanProcedureType.ChipTanFlickercode
net.dankito.fints.model.TanProcedureType.ChipTanUsb -> TanProcedureType.ChipTanUsb
net.dankito.fints.model.TanProcedureType.ChipTanQrCode -> TanProcedureType.ChipTanQrCode
net.dankito.fints.model.TanProcedureType.PhotoTan -> TanProcedureType.PhotoTan
net.dankito.fints.model.TanProcedureType.ChipTanPhotoTanMatrixCode -> TanProcedureType.ChipTanPhotoTanMatrixCode
net.dankito.fints.model.TanProcedureType.SmsTan -> TanProcedureType.SmsTan
net.dankito.fints.model.TanProcedureType.PushTan -> TanProcedureType.PushTan
net.dankito.fints.model.TanProcedureType.AppTan -> TanProcedureType.AppTan
}
}
@ -300,11 +301,12 @@ open class fints4javaModelMapper {
return when (type) {
TanProcedureType.EnterTan -> net.dankito.fints.model.TanProcedureType.EnterTan
TanProcedureType.ChipTanManuell -> net.dankito.fints.model.TanProcedureType.ChipTanManuell
TanProcedureType.ChipTanOptisch -> net.dankito.fints.model.TanProcedureType.ChipTanOptisch
TanProcedureType.ChipTanFlickercode -> net.dankito.fints.model.TanProcedureType.ChipTanFlickercode
TanProcedureType.ChipTanUsb -> net.dankito.fints.model.TanProcedureType.ChipTanUsb
TanProcedureType.ChipTanQrCode -> net.dankito.fints.model.TanProcedureType.ChipTanQrCode
TanProcedureType.PhotoTan -> net.dankito.fints.model.TanProcedureType.PhotoTan
TanProcedureType.ChipTanPhotoTanMatrixCode -> net.dankito.fints.model.TanProcedureType.ChipTanPhotoTanMatrixCode
TanProcedureType.SmsTan -> net.dankito.fints.model.TanProcedureType.SmsTan
TanProcedureType.PushTan -> net.dankito.fints.model.TanProcedureType.PushTan
TanProcedureType.AppTan -> net.dankito.fints.model.TanProcedureType.AppTan
}
}

View File

@ -10,6 +10,7 @@ import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherhe
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
import net.dankito.fints.messages.datenelemente.implementierte.tan.ZkaTanProcedure
import net.dankito.fints.messages.segmente.id.CustomerSegmentId
import net.dankito.fints.model.*
import net.dankito.fints.response.InstituteSegmentId
@ -694,10 +695,10 @@ open class FinTsClient @JvmOverloads constructor(
val tanProcedure = customer.selectedTanProcedure
return when (tanProcedure.type) {
TanProcedureType.ChipTanOptisch, TanProcedureType.ChipTanManuell ->
TanProcedureType.ChipTanFlickercode, TanProcedureType.ChipTanManuell ->
FlickerCodeTanChallenge(FlickerCodeDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
TanProcedureType.ChipTanQrCode, TanProcedureType.PhotoTan ->
TanProcedureType.ChipTanQrCode, TanProcedureType.ChipTanPhotoTanMatrixCode ->
ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
else -> TanChallenge(messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
@ -913,28 +914,71 @@ open class FinTsClient @JvmOverloads constructor(
}
protected open fun mapToTanProcedureType(parameters: TanProcedureParameters): TanProcedureType? {
val nameLowerCase = parameters.procedureName.toLowerCase()
val name = parameters.procedureName.toLowerCase()
return when {
nameLowerCase.contains("photo") -> TanProcedureType.PhotoTan
// names are like 'chipTAN (comfort) manuell', 'Smart(-)TAN plus (manuell)' and
// technical identification is 'HHD'. Exception: there's one that states itself as 'chipTAN (Manuell)'
// but its ZkaTanProcedure is set to 'HHDOPT1' -> handle ChipTanManuell before ChipTanFlickercode
parameters.zkaTanProcedure == ZkaTanProcedure.HHD || name.contains("manuell") ->
TanProcedureType.ChipTanManuell
nameLowerCase.contains("chiptan") -> {
return when {
nameLowerCase.contains("qr") -> TanProcedureType.ChipTanQrCode
nameLowerCase.contains("manuell") -> TanProcedureType.ChipTanManuell
else -> TanProcedureType.ChipTanOptisch
}
// names are like 'chipTAN optisch/comfort', 'SmartTAN (plus) optic/USB', 'chipTAN (Flicker)' and
// technical identification is 'HHDOPT1'
parameters.zkaTanProcedure == ZkaTanProcedure.HHDOPT1 ||
tanProcedureNameContains(name, "optisch", "optic", "comfort", "flicker") ->
TanProcedureType.ChipTanFlickercode
// 'Smart-TAN plus optisch / USB' seems to be a Flickertan procedure -> test for 'optisch' first
name.contains("usb") -> TanProcedureType.ChipTanUsb
// QRTAN+ from 1822 direct has nothing to do with chipTAN QR.
name.contains("qr") -> {
if (tanProcedureNameContains(name, "chipTAN", "Smart")) TanProcedureType.ChipTanQrCode
else TanProcedureType.AppTan
}
nameLowerCase.contains("push") -> return TanProcedureType.PushTan
nameLowerCase.contains("sms") || nameLowerCase.contains("mobile") -> return TanProcedureType.SmsTan
// photoTAN from Commerzbank (comdirect), Deutsche Bank, norisbank has nothing to do with chipTAN photo
name.contains("photo") -> {
// e.g. 'Smart-TAN photo' / description 'Challenge'
if (tanProcedureNameContains(name, "chipTAN", "Smart")) TanProcedureType.ChipTanPhotoTanMatrixCode
// e.g. 'photoTAN-Verfahren', description 'Freigabe durch photoTAN'
else TanProcedureType.AppTan
}
tanProcedureNameContains(name, "SMS", "mobile", "mTAN") -> TanProcedureType.SmsTan
// 'flateXSecure' identifies itself as 'PPTAN' instead of 'AppTAN'
// 'activeTAN-Verfahren' can actually be used either with an app or a reader; it's like chipTAN QR but without a chip card
tanProcedureNameContains(name, "push", "app", "BestSign", "SecureGo", "TAN2go", "activeTAN", "easyTAN", "SecurePlus", "TAN+")
|| technicalTanProcedureIdentificationContains(parameters, "SECURESIGN", "PPTAN") ->
TanProcedureType.AppTan
// TODO: what about other tan procedures we're not aware of?
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
else -> null
}
}
protected open fun tanProcedureNameContains(name: String, vararg namesToTest: String): Boolean {
namesToTest.forEach { nameToTest ->
if (name.contains(nameToTest.toLowerCase())) {
return true
}
}
return false
}
protected open fun technicalTanProcedureIdentificationContains(parameters: TanProcedureParameters, vararg valuesToTest: String): Boolean {
valuesToTest.forEach { valueToTest ->
if (parameters.technicalTanProcedureIdentification.contains(valueToTest, true)) {
return true
}
}
return false
}
protected open fun isJobSupported(account: AccountData, supportedJob: JobParameters): Boolean {
for (allowedJobName in account.allowedJobNames) {
if (allowedJobName == supportedJob.jobName) {

View File

@ -13,8 +13,6 @@ enum class ZkaTanProcedure {
// values not specified by standard but found out there in the wild
photoTAN,
appTAN
}

View File

@ -7,14 +7,16 @@ enum class TanProcedureType {
ChipTanManuell,
ChipTanOptisch,
ChipTanFlickercode,
ChipTanUsb,
ChipTanQrCode,
PhotoTan,
ChipTanPhotoTanMatrixCode,
SmsTan,
PushTan
AppTan
}

View File

@ -390,7 +390,7 @@ open class ResponseParser @JvmOverloads constructor(
return ZkaTanProcedure.mobileTAN
}
if (lowerCaseMayZkaTanProcedure == "apptan") {
if (lowerCaseMayZkaTanProcedure == "apptan" || lowerCaseMayZkaTanProcedure == "phototan") {
return ZkaTanProcedure.appTAN
}

View File

@ -37,7 +37,7 @@ abstract class FinTsTestBase {
const val ControlReference = "4477"
val Customer = CustomerData(CustomerId, Pin, selectedTanProcedure = TanProcedure("chipTAN-optisch", SecurityFunction, TanProcedureType.ChipTanOptisch), selectedLanguage = Language)
val Customer = CustomerData(CustomerId, Pin, selectedTanProcedure = TanProcedure("chipTAN-optisch", SecurityFunction, TanProcedureType.ChipTanFlickercode), selectedLanguage = Language)
val Currency = "EUR"

View File

@ -88,12 +88,12 @@ open class hbci4jModelMapper {
net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanQrCode, code)
}
else {
net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanOptisch, code)
net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanFlickercode, code)
}
}
displayNameLowerCase.contains("sms") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.SmsTan, code)
displayNameLowerCase.contains("push") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.PushTan, code)
displayNameLowerCase.contains("push") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.AppTan, code)
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
else -> null