Renamed TanProcedure to TanMethod in fints4k
This commit is contained in:
parent
d1ff6312ff
commit
f5f3f34d3b
|
@ -115,15 +115,15 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun getUsersTanProcedures(bank: BankData, callback: (FinTsClientResponse) -> Unit) {
|
open fun getUsersTanMethods(bank: BankData, callback: (FinTsClientResponse) -> Unit) {
|
||||||
getUsersTanProceduresInternal(bank) {
|
getUsersTanMethodsInternal(bank) {
|
||||||
callback(FinTsClientResponse(it))
|
callback(FinTsClientResponse(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getUsersTanProceduresInternal(bank: BankData, callback: (BankResponse) -> Unit) {
|
protected open fun getUsersTanMethodsInternal(bank: BankData, callback: (BankResponse) -> Unit) {
|
||||||
// just to ensure settings are in its initial state and that bank sends us bank parameter (BPD),
|
// just to ensure settings are in its initial state and that bank sends us bank parameter (BPD),
|
||||||
// user parameter (UPD) and allowed tan procedures for user (therefore the resetSelectedTanProcedure())
|
// user parameter (UPD) and allowed tan methods for user (therefore the resetSelectedTanMethod())
|
||||||
bank.resetBpdVersion()
|
bank.resetBpdVersion()
|
||||||
bank.resetUpdVersion()
|
bank.resetUpdVersion()
|
||||||
/**
|
/**
|
||||||
|
@ -132,38 +132,38 @@ open class FinTsClient(
|
||||||
* werden dann über den Rückmeldungscode=3920 zurückgemeldet. Im Rahmen dieses Prozesses darf keine UPD
|
* werden dann über den Rückmeldungscode=3920 zurückgemeldet. Im Rahmen dieses Prozesses darf keine UPD
|
||||||
* zurückgeliefert werden und die Durchführung anderer Geschäftsvorfälle ist in einem solchen Dialog nicht erlaubt.
|
* zurückgeliefert werden und die Durchführung anderer Geschäftsvorfälle ist in einem solchen Dialog nicht erlaubt.
|
||||||
*/
|
*/
|
||||||
bank.resetSelectedTanProcedure()
|
bank.resetSelectedTanMethod()
|
||||||
|
|
||||||
// this is the only case where Einschritt-TAN-Verfahren is accepted: to get user's TAN procedures
|
// this is the only case where Einschritt-TAN-Verfahren is accepted: to get user's TAN methods
|
||||||
val dialogContext = DialogContext(bank, product, versionOfSecurityProcedure = VersionDesSicherheitsverfahrens.Version_1)
|
val dialogContext = DialogContext(bank, product, versionOfSecurityMethod = VersionDesSicherheitsverfahrens.Version_1)
|
||||||
|
|
||||||
val message = messageBuilder.createInitDialogMessage(dialogContext)
|
val message = messageBuilder.createInitDialogMessage(dialogContext)
|
||||||
|
|
||||||
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
getAndHandleResponseForMessage(message, dialogContext) { response ->
|
||||||
closeDialog(dialogContext)
|
closeDialog(dialogContext)
|
||||||
|
|
||||||
handleGetUsersTanProceduresResponse(response, dialogContext, callback)
|
handleGetUsersTanMethodsResponse(response, dialogContext, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleGetUsersTanProceduresResponse(response: BankResponse, dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
protected open fun handleGetUsersTanMethodsResponse(response: BankResponse, dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
||||||
val getUsersTanProceduresResponse = GetUserTanProceduresResponse(response)
|
val getUsersTanMethodsResponse = GetUserTanMethodsResponse(response)
|
||||||
|
|
||||||
if (getUsersTanProceduresResponse.successful) { // TODO: really update data only on complete successfully response? as it may contain useful information anyway // TODO: extract method for this code part
|
if (getUsersTanMethodsResponse.successful) { // TODO: really update data only on complete successfully response? as it may contain useful information anyway // TODO: extract method for this code part
|
||||||
updateBankData(dialogContext.bank, getUsersTanProceduresResponse)
|
updateBankData(dialogContext.bank, getUsersTanMethodsResponse)
|
||||||
updateCustomerData(dialogContext.bank, getUsersTanProceduresResponse)
|
updateCustomerData(dialogContext.bank, getUsersTanMethodsResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// even though it is required by specification some banks don't support retrieving user's TAN procedure by setting TAN procedure to '999'
|
// even though it is required by specification some banks don't support retrieving user's TAN method by setting TAN method to '999'
|
||||||
if (bankDoesNotSupportRetrievingUsersTanProcedures(getUsersTanProceduresResponse)) {
|
if (bankDoesNotSupportRetrievingUsersTanMethods(getUsersTanMethodsResponse)) {
|
||||||
getBankAndCustomerInfoForNewUserViaAnonymousDialog(dialogContext.bank, callback) // TODO: should not be necessary anymore
|
getBankAndCustomerInfoForNewUserViaAnonymousDialog(dialogContext.bank, callback) // TODO: should not be necessary anymore
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callback(getUsersTanProceduresResponse)
|
callback(getUsersTanMethodsResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun bankDoesNotSupportRetrievingUsersTanProcedures(response: BankResponse): Boolean {
|
protected open fun bankDoesNotSupportRetrievingUsersTanMethods(response: BankResponse): Boolean {
|
||||||
return response.successful == false &&
|
return response.successful == false &&
|
||||||
response.segmentFeedbacks.flatMap { it.feedbacks }.firstOrNull { it.responseCode == 9200 &&
|
response.segmentFeedbacks.flatMap { it.feedbacks }.firstOrNull { it.responseCode == 9200 &&
|
||||||
it.message == "Gewähltes Zwei-Schritt-Verfahren nicht unterstützt." } != null
|
it.message == "Gewähltes Zwei-Schritt-Verfahren nicht unterstützt." } != null
|
||||||
|
@ -175,13 +175,13 @@ open class FinTsClient(
|
||||||
if (anonymousBankInfoResponse.successful == false) {
|
if (anonymousBankInfoResponse.successful == false) {
|
||||||
callback(anonymousBankInfoResponse)
|
callback(anonymousBankInfoResponse)
|
||||||
}
|
}
|
||||||
else if (bank.tanProceduresSupportedByBank.isEmpty()) { // should only be a theoretical error
|
else if (bank.tanMethodSupportedByBank.isEmpty()) { // should only be a theoretical error
|
||||||
callback(BankResponse(true,
|
callback(BankResponse(true,
|
||||||
errorMessage = "Die TAN Verfahren der Bank konnten nicht ermittelt werden")) // TODO: translate
|
errorMessage = "Die TAN Verfahren der Bank konnten nicht ermittelt werden")) // TODO: translate
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bank.tanProceduresAvailableForUser = bank.tanProceduresSupportedByBank
|
bank.tanMethodsAvailableForUser = bank.tanMethodSupportedByBank
|
||||||
getUsersTanProcedure(bank)
|
getUsersTanMethod(bank)
|
||||||
|
|
||||||
val dialogContext = DialogContext(bank, product)
|
val dialogContext = DialogContext(bank, product)
|
||||||
|
|
||||||
|
@ -246,26 +246,26 @@ open class FinTsClient(
|
||||||
val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs
|
val originalAreWeThatGentleToCloseDialogs = areWeThatGentleToCloseDialogs
|
||||||
areWeThatGentleToCloseDialogs = false
|
areWeThatGentleToCloseDialogs = false
|
||||||
|
|
||||||
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN procedures */
|
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
|
||||||
|
|
||||||
getUsersTanProceduresInternal(bank) { newUserInfoResponse ->
|
getUsersTanMethodsInternal(bank) { newUserInfoResponse ->
|
||||||
|
|
||||||
if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
|
if (newUserInfoResponse.successful == false) { // bank parameter (FinTS server address, ...) already seem to be wrong
|
||||||
callback(AddAccountResponse(newUserInfoResponse, bank))
|
callback(AddAccountResponse(newUserInfoResponse, bank))
|
||||||
return@getUsersTanProceduresInternal
|
return@getUsersTanMethodsInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// do not ask user for tan at this stage
|
// do not ask user for tan at this stage
|
||||||
var didOverwriteUserUnselectedTanProcedure = false
|
var didOverwriteUserUnselectedTanMethod = false
|
||||||
if (bank.isTanProcedureSelected == false && bank.tanProceduresAvailableForUser.isNotEmpty()) {
|
if (bank.isTanMethodSelected == false && bank.tanMethodsAvailableForUser.isNotEmpty()) {
|
||||||
|
|
||||||
if (bank.tanProceduresAvailableForUser.size == 1) { // user has only one TAN procedure -> set it and we're done
|
if (bank.tanMethodsAvailableForUser.size == 1) { // user has only one TAN method -> set it and we're done
|
||||||
bank.selectedTanProcedure = bank.tanProceduresAvailableForUser.first()
|
bank.selectedTanMethod = bank.tanMethodsAvailableForUser.first()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
didOverwriteUserUnselectedTanProcedure = true
|
didOverwriteUserUnselectedTanMethod = true
|
||||||
bank.selectedTanProcedure = selectSuggestedTanProcedure(bank) ?: bank.tanProceduresAvailableForUser.first()
|
bank.selectedTanMethod = selectSuggestedTanMethod(bank) ?: bank.tanMethodsAvailableForUser.first() // TODO: make settable which TAN method is the selected one, e.g. for a REST API a non visible one
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ open class FinTsClient(
|
||||||
|
|
||||||
/* Fourth dialog: Try to retrieve account balances and transactions of last 90 days without TAN */
|
/* Fourth dialog: Try to retrieve account balances and transactions of last 90 days without TAN */
|
||||||
|
|
||||||
addAccountGetAccountBalancesAndTransactions(bank, newUserInfoResponse, didOverwriteUserUnselectedTanProcedure,
|
addAccountGetAccountBalancesAndTransactions(bank, newUserInfoResponse, didOverwriteUserUnselectedTanMethod,
|
||||||
originalAreWeThatGentleToCloseDialogs, callback)
|
originalAreWeThatGentleToCloseDialogs, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,7 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun addAccountGetAccountBalancesAndTransactions(bank: BankData, newUserInfoResponse: BankResponse,
|
protected open fun addAccountGetAccountBalancesAndTransactions(bank: BankData, newUserInfoResponse: BankResponse,
|
||||||
didOverwriteUserUnselectedTanProcedure: Boolean, originalAreWeThatGentleToCloseDialogs: Boolean,
|
didOverwriteUserUnselectedTanMethod: Boolean, originalAreWeThatGentleToCloseDialogs: Boolean,
|
||||||
callback: (AddAccountResponse) -> Unit) {
|
callback: (AddAccountResponse) -> Unit) {
|
||||||
// TODO: or add a default RetrievedAccountData instance for each account?
|
// TODO: or add a default RetrievedAccountData instance for each account?
|
||||||
val retrievedAccountData = mutableListOf<RetrievedAccountData>()
|
val retrievedAccountData = mutableListOf<RetrievedAccountData>()
|
||||||
|
@ -303,7 +303,7 @@ open class FinTsClient(
|
||||||
var countRetrievedAccounts = 0
|
var countRetrievedAccounts = 0
|
||||||
|
|
||||||
if (countAccountSupportingRetrievingTransactions == 0) {
|
if (countAccountSupportingRetrievingTransactions == 0) {
|
||||||
addAccountAfterRetrievingTransactions(bank, newUserInfoResponse, didOverwriteUserUnselectedTanProcedure,
|
addAccountAfterRetrievingTransactions(bank, newUserInfoResponse, didOverwriteUserUnselectedTanMethod,
|
||||||
originalAreWeThatGentleToCloseDialogs, retrievedAccountData, callback)
|
originalAreWeThatGentleToCloseDialogs, retrievedAccountData, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ open class FinTsClient(
|
||||||
|
|
||||||
countRetrievedAccounts++
|
countRetrievedAccounts++
|
||||||
if (countRetrievedAccounts == countAccountSupportingRetrievingTransactions) {
|
if (countRetrievedAccounts == countAccountSupportingRetrievingTransactions) {
|
||||||
addAccountAfterRetrievingTransactions(bank, newUserInfoResponse, didOverwriteUserUnselectedTanProcedure, originalAreWeThatGentleToCloseDialogs,
|
addAccountAfterRetrievingTransactions(bank, newUserInfoResponse, didOverwriteUserUnselectedTanMethod, originalAreWeThatGentleToCloseDialogs,
|
||||||
retrievedAccountData, callback)
|
retrievedAccountData, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,11 +321,11 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun addAccountAfterRetrievingTransactions(bank: BankData, newUserInfoResponse: BankResponse,
|
protected open fun addAccountAfterRetrievingTransactions(bank: BankData, newUserInfoResponse: BankResponse,
|
||||||
didOverwriteUserUnselectedTanProcedure: Boolean, originalAreWeThatGentleToCloseDialogs: Boolean,
|
didOverwriteUserUnselectedTanMethod: Boolean, originalAreWeThatGentleToCloseDialogs: Boolean,
|
||||||
retrievedAccountData: List<RetrievedAccountData>,
|
retrievedAccountData: List<RetrievedAccountData>,
|
||||||
callback: (AddAccountResponse) -> Unit) {
|
callback: (AddAccountResponse) -> Unit) {
|
||||||
if (didOverwriteUserUnselectedTanProcedure) {
|
if (didOverwriteUserUnselectedTanMethod) {
|
||||||
bank.resetSelectedTanProcedure()
|
bank.resetSelectedTanMethod()
|
||||||
}
|
}
|
||||||
|
|
||||||
areWeThatGentleToCloseDialogs = originalAreWeThatGentleToCloseDialogs
|
areWeThatGentleToCloseDialogs = originalAreWeThatGentleToCloseDialogs
|
||||||
|
@ -440,7 +440,7 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleGetTanMediaListResponse(response: BankResponse, bank: BankData, callback: (GetTanMediaListResponse) -> Unit) {
|
private fun handleGetTanMediaListResponse(response: BankResponse, bank: BankData, callback: (GetTanMediaListResponse) -> Unit) {
|
||||||
// TAN media list (= TAN generator list) is only returned for users with chipTAN TAN procedures
|
// TAN media list (= TAN generator list) is only returned for users with chipTAN TAN methods
|
||||||
val tanMediaList = if (response.successful == false) null
|
val tanMediaList = if (response.successful == false) null
|
||||||
else response.getFirstSegmentById<TanMediaList>(InstituteSegmentId.TanMediaList)
|
else response.getFirstSegmentById<TanMediaList>(InstituteSegmentId.TanMediaList)
|
||||||
|
|
||||||
|
@ -532,16 +532,16 @@ open class FinTsClient(
|
||||||
|
|
||||||
protected open fun initDialog(dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
protected open fun initDialog(dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
||||||
|
|
||||||
// we first need to retrieve supported tan procedures and jobs before we can do anything
|
// we first need to retrieve supported tan methods and jobs before we can do anything
|
||||||
ensureBasicBankDataRetrieved(dialogContext.bank) { retrieveBasicBankDataResponse ->
|
ensureBasicBankDataRetrieved(dialogContext.bank) { retrieveBasicBankDataResponse ->
|
||||||
if (retrieveBasicBankDataResponse.successful == false) {
|
if (retrieveBasicBankDataResponse.successful == false) {
|
||||||
callback(retrieveBasicBankDataResponse)
|
callback(retrieveBasicBankDataResponse)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// as in the next step we have to supply user's tan procedure, ensure user selected his or her
|
// as in the next step we have to supply user's tan method, ensure user selected his or her
|
||||||
ensureTanProcedureIsSelected(dialogContext.bank) { tanProcedureSelectedResponse ->
|
ensureTanMethodIsSelected(dialogContext.bank) { tanMethodSelectedResponse ->
|
||||||
if (tanProcedureSelectedResponse.successful == false) {
|
if (tanMethodSelectedResponse.successful == false) {
|
||||||
callback(tanProcedureSelectedResponse)
|
callback(tanMethodSelectedResponse)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
initDialogAfterSuccessfulChecks(dialogContext, callback)
|
initDialogAfterSuccessfulChecks(dialogContext, callback)
|
||||||
|
@ -595,13 +595,13 @@ open class FinTsClient(
|
||||||
|
|
||||||
|
|
||||||
protected open fun ensureBasicBankDataRetrieved(bank: BankData, callback: (BankResponse) -> Unit) {
|
protected open fun ensureBasicBankDataRetrieved(bank: BankData, callback: (BankResponse) -> Unit) {
|
||||||
if (bank.tanProceduresSupportedByBank.isEmpty() || bank.supportedJobs.isEmpty()) {
|
if (bank.tanMethodSupportedByBank.isEmpty() || bank.supportedJobs.isEmpty()) {
|
||||||
getUsersTanProceduresInternal(bank) { getBankInfoResponse ->
|
getUsersTanMethodsInternal(bank) { getBankInfoResponse ->
|
||||||
if (getBankInfoResponse.successful == false || bank.tanProceduresSupportedByBank.isEmpty()
|
if (getBankInfoResponse.successful == false || bank.tanMethodSupportedByBank.isEmpty()
|
||||||
|| bank.supportedJobs.isEmpty()) {
|
|| bank.supportedJobs.isEmpty()) {
|
||||||
|
|
||||||
callback(BankResponse(false, errorMessage =
|
callback(BankResponse(false, errorMessage =
|
||||||
"Could not retrieve basic bank data like supported tan procedures or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser
|
"Could not retrieve basic bank data like supported tan methods or supported jobs")) // TODO: translate // TODO: add as messageToShowToUser
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callback(BankResponse(true))
|
callback(BankResponse(true))
|
||||||
|
@ -613,48 +613,48 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun ensureTanProcedureIsSelected(bank: BankData, callback: (BankResponse) -> Unit) {
|
protected open fun ensureTanMethodIsSelected(bank: BankData, callback: (BankResponse) -> Unit) {
|
||||||
if (bank.isTanProcedureSelected == false) {
|
if (bank.isTanMethodSelected == false) {
|
||||||
if (bank.tanProceduresAvailableForUser.isEmpty()) {
|
if (bank.tanMethodsAvailableForUser.isEmpty()) {
|
||||||
getUsersTanProceduresInternal(bank) {
|
getUsersTanMethodsInternal(bank) {
|
||||||
if (bank.tanProceduresAvailableForUser.isEmpty()) { // could not retrieve supported tan procedures for user
|
if (bank.tanMethodsAvailableForUser.isEmpty()) { // could not retrieve supported tan methods for user
|
||||||
callback(BankResponse(false, noTanProcedureSelected = true))
|
callback(BankResponse(false, noTanMethodSelected = true))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getUsersTanProcedure(bank)
|
getUsersTanMethod(bank)
|
||||||
callback(BankResponse(bank.isTanProcedureSelected, noTanProcedureSelected = !!!bank.isTanProcedureSelected))
|
callback(BankResponse(bank.isTanMethodSelected, noTanMethodSelected = !!!bank.isTanMethodSelected))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getUsersTanProcedure(bank)
|
getUsersTanMethod(bank)
|
||||||
callback(BankResponse(bank.isTanProcedureSelected, noTanProcedureSelected = !!!bank.isTanProcedureSelected))
|
callback(BankResponse(bank.isTanMethodSelected, noTanMethodSelected = !!!bank.isTanMethodSelected))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callback(BankResponse(bank.isTanProcedureSelected, noTanProcedureSelected = !!!bank.isTanProcedureSelected))
|
callback(BankResponse(bank.isTanMethodSelected, noTanMethodSelected = !!!bank.isTanMethodSelected))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getUsersTanProcedure(bank: BankData) {
|
protected open fun getUsersTanMethod(bank: BankData) {
|
||||||
if (bank.tanProceduresAvailableForUser.size == 1) { // user has only one TAN procedure -> set it and we're done
|
if (bank.tanMethodsAvailableForUser.size == 1) { // user has only one TAN method -> set it and we're done
|
||||||
bank.selectedTanProcedure = bank.tanProceduresAvailableForUser.first()
|
bank.selectedTanMethod = bank.tanMethodsAvailableForUser.first()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// we know user's supported tan procedures, now ask user which one to select
|
// we know user's supported tan methods, now ask user which one to select
|
||||||
callback.askUserForTanProcedure(bank.tanProceduresAvailableForUser, selectSuggestedTanProcedure(bank)) { selectedTanProcedure ->
|
callback.askUserForTanMethod(bank.tanMethodsAvailableForUser, selectSuggestedTanMethod(bank)) { selectedTanMethod ->
|
||||||
selectedTanProcedure?.let {
|
selectedTanMethod?.let {
|
||||||
bank.selectedTanProcedure = selectedTanProcedure
|
bank.selectedTanMethod = selectedTanMethod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun selectSuggestedTanProcedure(bank: BankData): TanProcedure? {
|
protected open fun selectSuggestedTanMethod(bank: BankData): TanMethod? {
|
||||||
return bank.tanProceduresAvailableForUser.firstOrNull { it.type != TanProcedureType.ChipTanUsb && it.type != TanProcedureType.SmsTan && it.type != TanProcedureType.ChipTanManuell }
|
return bank.tanMethodsAvailableForUser.firstOrNull { it.type != TanMethodType.ChipTanUsb && it.type != TanMethodType.SmsTan && it.type != TanMethodType.ChipTanManuell }
|
||||||
?: bank.tanProceduresAvailableForUser.firstOrNull { it.type != TanProcedureType.ChipTanUsb && it.type != TanProcedureType.SmsTan }
|
?: bank.tanMethodsAvailableForUser.firstOrNull { it.type != TanMethodType.ChipTanUsb && it.type != TanMethodType.SmsTan }
|
||||||
?: bank.tanProceduresAvailableForUser.firstOrNull { it.type != TanProcedureType.ChipTanUsb }
|
?: bank.tanMethodsAvailableForUser.firstOrNull { it.type != TanMethodType.ChipTanUsb }
|
||||||
?: bank.tanProceduresAvailableForUser.firstOrNull()
|
?: bank.tanMethodsAvailableForUser.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -855,36 +855,36 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createTanChallenge(tanResponse: TanResponse, bank: BankData): TanChallenge {
|
protected open fun createTanChallenge(tanResponse: TanResponse, bank: BankData): TanChallenge {
|
||||||
// TODO: is this true for all tan procedures?
|
// TODO: is this true for all tan methods?
|
||||||
val messageToShowToUser = tanResponse.challenge ?: ""
|
val messageToShowToUser = tanResponse.challenge ?: ""
|
||||||
val challenge = tanResponse.challengeHHD_UC ?: ""
|
val challenge = tanResponse.challengeHHD_UC ?: ""
|
||||||
val tanProcedure = bank.selectedTanProcedure
|
val tanMethod = bank.selectedTanMethod
|
||||||
|
|
||||||
return when (tanProcedure.type) {
|
return when (tanMethod.type) {
|
||||||
TanProcedureType.ChipTanFlickercode ->
|
TanMethodType.ChipTanFlickercode ->
|
||||||
FlickerCodeTanChallenge(FlickerCodeDecoder().decodeChallenge(challenge, tanProcedure.hhdVersion ?: HHDVersion.HHD_1_4), // HHD 1.4 is currently the most used version
|
FlickerCodeTanChallenge(FlickerCodeDecoder().decodeChallenge(challenge, tanMethod.hhdVersion ?: HHDVersion.HHD_1_4), // HHD 1.4 is currently the most used version
|
||||||
messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
|
messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier)
|
||||||
|
|
||||||
TanProcedureType.ChipTanQrCode, TanProcedureType.ChipTanPhotoTanMatrixCode,
|
TanMethodType.ChipTanQrCode, TanMethodType.ChipTanPhotoTanMatrixCode,
|
||||||
TanProcedureType.QrCode, TanProcedureType.photoTan ->
|
TanMethodType.QrCode, TanMethodType.photoTan ->
|
||||||
ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
|
ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier)
|
||||||
|
|
||||||
else -> TanChallenge(messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
|
else -> TanChallenge(messageToShowToUser, challenge, tanMethod, tanResponse.tanMediaIdentifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleEnterTanResult(enteredTanResult: EnterTanResult, tanResponse: TanResponse, response: BankResponse,
|
protected open fun handleEnterTanResult(enteredTanResult: EnterTanResult, tanResponse: TanResponse, response: BankResponse,
|
||||||
dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
||||||
|
|
||||||
if (enteredTanResult.changeTanProcedureTo != null) {
|
if (enteredTanResult.changeTanMethodTo != null) {
|
||||||
handleUserAsksToChangeTanProcedureAndResendLastMessage(enteredTanResult.changeTanProcedureTo, dialogContext, callback)
|
handleUserAsksToChangeTanMethodAndResendLastMessage(enteredTanResult.changeTanMethodTo, dialogContext, callback)
|
||||||
}
|
}
|
||||||
else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) {
|
else if (enteredTanResult.changeTanMediumTo is TanGeneratorTanMedium) {
|
||||||
handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo, dialogContext,
|
handleUserAsksToChangeTanMediumAndResendLastMessage(enteredTanResult.changeTanMediumTo, dialogContext,
|
||||||
enteredTanResult.changeTanMediumResultCallback, callback)
|
enteredTanResult.changeTanMediumResultCallback, callback)
|
||||||
}
|
}
|
||||||
else if (enteredTanResult.enteredTan == null) {
|
else if (enteredTanResult.enteredTan == null) {
|
||||||
// i tried to send a HKTAN with cancelJob = true but then i saw there are no tan procedures that support cancellation (at least not at my bank)
|
// i tried to send a HKTAN with cancelJob = true but then i saw there are no tan methods that support cancellation (at least not at my bank)
|
||||||
// but it's not required anyway, tan times out after some time. Simply don't respond anything and close dialog
|
// but it's not required anyway, tan times out after some time. Simply don't respond anything and close dialog
|
||||||
response.tanRequiredButUserDidNotEnterOne = true
|
response.tanRequiredButUserDidNotEnterOne = true
|
||||||
|
|
||||||
|
@ -902,9 +902,9 @@ open class FinTsClient(
|
||||||
getAndHandleResponseForMessage(message, dialogContext, callback)
|
getAndHandleResponseForMessage(message, dialogContext, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleUserAsksToChangeTanProcedureAndResendLastMessage(changeTanProcedureTo: TanProcedure, dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
protected open fun handleUserAsksToChangeTanMethodAndResendLastMessage(changeTanMethodTo: TanMethod, dialogContext: DialogContext, callback: (BankResponse) -> Unit) {
|
||||||
|
|
||||||
dialogContext.bank.selectedTanProcedure = changeTanProcedureTo
|
dialogContext.bank.selectedTanMethod = changeTanMethodTo
|
||||||
|
|
||||||
|
|
||||||
val lastCreatedMessage = dialogContext.currentMessage
|
val lastCreatedMessage = dialogContext.currentMessage
|
||||||
|
@ -958,7 +958,7 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN procedure. Probably an internal programming error." // TODO: translate
|
val errorMessage = "There's no last action (like retrieve account transactions, transfer money, ...) to re-send with new TAN method. Probably an internal programming error." // TODO: translate
|
||||||
callback(BankResponse(false, errorMessage = errorMessage)) // should never come to this
|
callback(BankResponse(false, errorMessage = errorMessage)) // should never come to this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -982,7 +982,7 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
|
|
||||||
response.getFirstSegmentById<TanInfo>(InstituteSegmentId.TanInfo)?.let { tanInfo ->
|
response.getFirstSegmentById<TanInfo>(InstituteSegmentId.TanInfo)?.let { tanInfo ->
|
||||||
bank.tanProceduresSupportedByBank = mapToTanProcedures(tanInfo)
|
bank.tanMethodSupportedByBank = mapToTanMethods(tanInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
response.getFirstSegmentById<CommunicationInfo>(InstituteSegmentId.CommunicationInfo)?.let { communicationInfo ->
|
response.getFirstSegmentById<CommunicationInfo>(InstituteSegmentId.CommunicationInfo)?.let { communicationInfo ->
|
||||||
|
@ -1097,17 +1097,17 @@ open class FinTsClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.supportedTanProceduresForUser.isNotEmpty()) {
|
if (response.supportedTanMethodsForUser.isNotEmpty()) {
|
||||||
bank.tanProceduresAvailableForUser = response.supportedTanProceduresForUser.mapNotNull { findTanProcedure(it, bank) }
|
bank.tanMethodsAvailableForUser = response.supportedTanMethodsForUser.mapNotNull { findTanMethod(it, bank) }
|
||||||
|
|
||||||
if (bank.tanProceduresAvailableForUser.firstOrNull { it.securityFunction == bank.selectedTanProcedure.securityFunction } == null) { // supportedTanProcedures don't contain selectedTanProcedure anymore
|
if (bank.tanMethodsAvailableForUser.firstOrNull { it.securityFunction == bank.selectedTanMethod.securityFunction } == null) { // supportedTanMethods don't contain selectedTanMethod anymore
|
||||||
bank.resetSelectedTanProcedure()
|
bank.resetSelectedTanMethod()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findTanProcedure(securityFunction: Sicherheitsfunktion, bank: BankData): TanProcedure? {
|
protected open fun findTanMethod(securityFunction: Sicherheitsfunktion, bank: BankData): TanMethod? {
|
||||||
return bank.tanProceduresSupportedByBank.firstOrNull { it.securityFunction == securityFunction }
|
return bank.tanMethodSupportedByBank.firstOrNull { it.securityFunction == securityFunction }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun setAllowedJobsForAccount(bank: BankData, account: AccountData, supportedJobs: List<JobParameters>) {
|
protected open fun setAllowedJobsForAccount(bank: BankData, account: AccountData, supportedJobs: List<JobParameters>) {
|
||||||
|
@ -1127,83 +1127,83 @@ open class FinTsClient(
|
||||||
account.setSupportsFeature(AccountFeature.InstantPayment, messageBuilder.supportsSepaInstantPaymentBankTransfer(bank, account))
|
account.setSupportsFeature(AccountFeature.InstantPayment, messageBuilder.supportsSepaInstantPaymentBankTransfer(bank, account))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapToTanProcedures(tanInfo: TanInfo): List<TanProcedure> {
|
protected open fun mapToTanMethods(tanInfo: TanInfo): List<TanMethod> {
|
||||||
return tanInfo.tanProcedureParameters.procedureParameters.mapNotNull {
|
return tanInfo.tanProcedureParameters.methodParameters.mapNotNull {
|
||||||
mapToTanProcedure(it)
|
mapToTanMethod(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapToTanProcedure(parameters: TanProcedureParameters): TanProcedure? {
|
protected open fun mapToTanMethod(parameters: TanMethodParameters): TanMethod? {
|
||||||
val procedureName = parameters.procedureName
|
val methodName = parameters.methodName
|
||||||
|
|
||||||
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
||||||
if (procedureName.toLowerCase() == "itan") {
|
if (methodName.toLowerCase() == "itan") {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return TanProcedure(procedureName, parameters.securityFunction,
|
return TanMethod(methodName, parameters.securityFunction,
|
||||||
mapToTanProcedureType(parameters) ?: TanProcedureType.EnterTan, mapHhdVersion(parameters),
|
mapToTanMethodType(parameters) ?: TanMethodType.EnterTan, mapHhdVersion(parameters),
|
||||||
parameters.maxTanInputLength, parameters.allowedTanFormat,
|
parameters.maxTanInputLength, parameters.allowedTanFormat,
|
||||||
parameters.nameOfTanMediaRequired == BezeichnungDesTanMediumsErforderlich.BezeichnungDesTanMediumsMussAngegebenWerden)
|
parameters.nameOfTanMediaRequired == BezeichnungDesTanMediumsErforderlich.BezeichnungDesTanMediumsMussAngegebenWerden)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapToTanProcedureType(parameters: TanProcedureParameters): TanProcedureType? {
|
protected open fun mapToTanMethodType(parameters: TanMethodParameters): TanMethodType? {
|
||||||
val name = parameters.procedureName.toLowerCase()
|
val name = parameters.methodName.toLowerCase()
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
// names are like 'chipTAN (comfort) manuell', 'Smart(-)TAN plus (manuell)' and
|
// 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)'
|
// 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
|
// but its ZkaTanMethod is set to 'HHDOPT1' -> handle ChipTanManuell before ChipTanFlickercode
|
||||||
parameters.zkaTanProcedure == ZkaTanProcedure.HHD || name.contains("manuell") ->
|
parameters.zkaTanMethod == ZkaTanMethod.HHD || name.contains("manuell") ->
|
||||||
TanProcedureType.ChipTanManuell
|
TanMethodType.ChipTanManuell
|
||||||
|
|
||||||
// names are like 'chipTAN optisch/comfort', 'SmartTAN (plus) optic/USB', 'chipTAN (Flicker)' and
|
// names are like 'chipTAN optisch/comfort', 'SmartTAN (plus) optic/USB', 'chipTAN (Flicker)' and
|
||||||
// technical identification is 'HHDOPT1'
|
// technical identification is 'HHDOPT1'
|
||||||
parameters.zkaTanProcedure == ZkaTanProcedure.HHDOPT1 ||
|
parameters.zkaTanMethod == ZkaTanMethod.HHDOPT1 ||
|
||||||
tanProcedureNameContains(name, "optisch", "optic", "comfort", "flicker") ->
|
tanMethodNameContains(name, "optisch", "optic", "comfort", "flicker") ->
|
||||||
TanProcedureType.ChipTanFlickercode
|
TanMethodType.ChipTanFlickercode
|
||||||
|
|
||||||
// 'Smart-TAN plus optisch / USB' seems to be a Flickertan procedure -> test for 'optisch' first
|
// 'Smart-TAN plus optisch / USB' seems to be a Flickertan method -> test for 'optisch' first
|
||||||
name.contains("usb") -> TanProcedureType.ChipTanUsb
|
name.contains("usb") -> TanMethodType.ChipTanUsb
|
||||||
|
|
||||||
// QRTAN+ from 1822 direct has nothing to do with chipTAN QR.
|
// QRTAN+ from 1822 direct has nothing to do with chipTAN QR.
|
||||||
name.contains("qr") -> {
|
name.contains("qr") -> {
|
||||||
if (tanProcedureNameContains(name, "chipTAN", "Smart")) TanProcedureType.ChipTanQrCode
|
if (tanMethodNameContains(name, "chipTAN", "Smart")) TanMethodType.ChipTanQrCode
|
||||||
else TanProcedureType.QrCode
|
else TanMethodType.QrCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// photoTAN from Commerzbank (comdirect), Deutsche Bank, norisbank has nothing to do with chipTAN photo
|
// photoTAN from Commerzbank (comdirect), Deutsche Bank, norisbank has nothing to do with chipTAN photo
|
||||||
name.contains("photo") -> {
|
name.contains("photo") -> {
|
||||||
// e.g. 'Smart-TAN photo' / description 'Challenge'
|
// e.g. 'Smart-TAN photo' / description 'Challenge'
|
||||||
if (tanProcedureNameContains(name, "chipTAN", "Smart")) TanProcedureType.ChipTanPhotoTanMatrixCode
|
if (tanMethodNameContains(name, "chipTAN", "Smart")) TanMethodType.ChipTanPhotoTanMatrixCode
|
||||||
// e.g. 'photoTAN-Verfahren', description 'Freigabe durch photoTAN'
|
// e.g. 'photoTAN-Verfahren', description 'Freigabe durch photoTAN'
|
||||||
else TanProcedureType.photoTan
|
else TanMethodType.photoTan
|
||||||
}
|
}
|
||||||
|
|
||||||
tanProcedureNameContains(name, "SMS", "mobile", "mTAN") -> TanProcedureType.SmsTan
|
tanMethodNameContains(name, "SMS", "mobile", "mTAN") -> TanMethodType.SmsTan
|
||||||
|
|
||||||
// 'flateXSecure' identifies itself as 'PPTAN' instead of 'AppTAN'
|
// '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
|
// '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+")
|
tanMethodNameContains(name, "push", "app", "BestSign", "SecureGo", "TAN2go", "activeTAN", "easyTAN", "SecurePlus", "TAN+")
|
||||||
|| technicalTanProcedureIdentificationContains(parameters, "SECURESIGN", "PPTAN") ->
|
|| technicalTanMethodIdentificationContains(parameters, "SECURESIGN", "PPTAN") ->
|
||||||
TanProcedureType.AppTan
|
TanMethodType.AppTan
|
||||||
|
|
||||||
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
// we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapHhdVersion(parameters: TanProcedureParameters): HHDVersion? {
|
protected open fun mapHhdVersion(parameters: TanMethodParameters): HHDVersion? {
|
||||||
return when {
|
return when {
|
||||||
technicalTanProcedureIdentificationContains(parameters, "HHD1.4") -> HHDVersion.HHD_1_4
|
technicalTanMethodIdentificationContains(parameters, "HHD1.4") -> HHDVersion.HHD_1_4
|
||||||
technicalTanProcedureIdentificationContains(parameters, "HHD1.3") -> HHDVersion.HHD_1_3
|
technicalTanMethodIdentificationContains(parameters, "HHD1.3") -> HHDVersion.HHD_1_3
|
||||||
parameters.versionZkaTanProcedure?.contains("1.4") == true -> HHDVersion.HHD_1_4
|
parameters.versionZkaTanMethod?.contains("1.4") == true -> HHDVersion.HHD_1_4
|
||||||
parameters.versionZkaTanProcedure?.contains("1.3") == true -> HHDVersion.HHD_1_4
|
parameters.versionZkaTanMethod?.contains("1.3") == true -> HHDVersion.HHD_1_4
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun tanProcedureNameContains(name: String, vararg namesToTest: String): Boolean {
|
protected open fun tanMethodNameContains(name: String, vararg namesToTest: String): Boolean {
|
||||||
namesToTest.forEach { nameToTest ->
|
namesToTest.forEach { nameToTest ->
|
||||||
if (name.contains(nameToTest.toLowerCase())) {
|
if (name.contains(nameToTest.toLowerCase())) {
|
||||||
return true
|
return true
|
||||||
|
@ -1213,9 +1213,9 @@ open class FinTsClient(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun technicalTanProcedureIdentificationContains(parameters: TanProcedureParameters, vararg valuesToTest: String): Boolean {
|
protected open fun technicalTanMethodIdentificationContains(parameters: TanMethodParameters, vararg valuesToTest: String): Boolean {
|
||||||
valuesToTest.forEach { valueToTest ->
|
valuesToTest.forEach { valueToTest ->
|
||||||
if (parameters.technicalTanProcedureIdentification.contains(valueToTest, true)) {
|
if (parameters.technicalTanMethodIdentification.contains(valueToTest, true)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,16 @@ import net.dankito.banking.fints.model.*
|
||||||
interface FinTsClientCallback {
|
interface FinTsClientCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When user did not select a TAN procedure, this method gets called so that user selects one.
|
* When user did not select a TAN method, this method gets called so that user selects one.
|
||||||
*
|
*
|
||||||
* As almost all FinTS messages need the selected TAN procedure, this method gets called quite early.
|
* As almost all FinTS messages need the selected TAN method, this method gets called quite early.
|
||||||
*
|
*
|
||||||
* As a simplification fints4k already suggests which TAN procedure may is the best one for user.
|
* As a simplification fints4k already suggests which TAN method may is the best one for user.
|
||||||
*
|
*
|
||||||
* If you do not support an enter tan dialog or if your enter tan dialog supports selecting a TAN procedure, it's
|
* If you do not support an enter tan dialog or if your enter tan dialog supports selecting a TAN method, it's
|
||||||
* best returning [suggestedTanProcedure] and to not show an extra select TAN procedure dialog.
|
* best returning [suggestedTanMethod] and to not show an extra select TAN method dialog.
|
||||||
*/
|
*/
|
||||||
fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?, callback: (TanProcedure?) -> Unit)
|
fun askUserForTanMethod(supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit)
|
||||||
|
|
||||||
fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit)
|
fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit)
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ import net.dankito.banking.fints.model.*
|
||||||
|
|
||||||
open class NoOpFinTsClientCallback : FinTsClientCallback {
|
open class NoOpFinTsClientCallback : FinTsClientCallback {
|
||||||
|
|
||||||
override fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>,
|
override fun askUserForTanMethod(supportedTanMethods: List<TanMethod>,
|
||||||
suggestedTanProcedure: TanProcedure?, callback: (TanProcedure?) -> Unit) {
|
suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
|
||||||
|
|
||||||
callback(suggestedTanProcedure)
|
callback(suggestedTanMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||||
|
|
|
@ -7,13 +7,13 @@ import net.dankito.banking.fints.model.*
|
||||||
open class SimpleFinTsClientCallback(
|
open class SimpleFinTsClientCallback(
|
||||||
protected val enterTan: ((bank: BankData, tanChallenge: TanChallenge) -> EnterTanResult)? = null,
|
protected val enterTan: ((bank: BankData, tanChallenge: TanChallenge) -> EnterTanResult)? = null,
|
||||||
protected val enterTanGeneratorAtc: ((bank: BankData, tanMedium: TanGeneratorTanMedium) -> EnterTanGeneratorAtcResult)? = null,
|
protected val enterTanGeneratorAtc: ((bank: BankData, tanMedium: TanGeneratorTanMedium) -> EnterTanGeneratorAtcResult)? = null,
|
||||||
protected val askUserForTanProcedure: ((supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?) -> TanProcedure?)? = null
|
protected val askUserForTanMethod: ((supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?) -> TanMethod?)? = null
|
||||||
) : FinTsClientCallback {
|
) : FinTsClientCallback {
|
||||||
|
|
||||||
override fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>,
|
override fun askUserForTanMethod(supportedTanMethods: List<TanMethod>,
|
||||||
suggestedTanProcedure: TanProcedure?, callback: (TanProcedure?) -> Unit) {
|
suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
|
||||||
|
|
||||||
callback(askUserForTanProcedure?.invoke(supportedTanProcedures, suggestedTanProcedure) ?: suggestedTanProcedure)
|
callback(askUserForTanMethod?.invoke(supportedTanMethods, suggestedTanMethod) ?: suggestedTanMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||||
|
|
|
@ -117,7 +117,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
||||||
if (segmentIdForTwoStepTanProcess != null) {
|
if (segmentIdForTwoStepTanProcess != null) {
|
||||||
segments.add(createTwoStepTanSegment(segmentIdForTwoStepTanProcess, dialogContext))
|
segments.add(createTwoStepTanSegment(segmentIdForTwoStepTanProcess, dialogContext))
|
||||||
}
|
}
|
||||||
else if (dialogContext.bank.isTanProcedureSelected) {
|
else if (dialogContext.bank.isTanMethodSelected) {
|
||||||
segments.add(createTwoStepTanSegment(CustomerSegmentId.Identification, dialogContext))
|
segments.add(createTwoStepTanSegment(CustomerSegmentId.Identification, dialogContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
||||||
protected open fun getTanMediaIdentifierIfRequired(dialogContext: DialogContext): String? {
|
protected open fun getTanMediaIdentifierIfRequired(dialogContext: DialogContext): String? {
|
||||||
val bank = dialogContext.bank
|
val bank = dialogContext.bank
|
||||||
|
|
||||||
if (bank.isTanProcedureSelected && bank.selectedTanProcedure.nameOfTanMediaRequired) {
|
if (bank.isTanMethodSelected && bank.selectedTanMethod.nameOfTanMediaRequired) {
|
||||||
return bank.tanMedia.firstOrNull { it.mediumName != null }?.mediumName
|
return bank.tanMedia.firstOrNull { it.mediumName != null }?.mediumName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package net.dankito.banking.fints.messages.datenelemente.implementierte.tan
|
package net.dankito.banking.fints.messages.datenelemente.implementierte.tan
|
||||||
|
|
||||||
|
|
||||||
enum class ZkaTanProcedure {
|
enum class ZkaTanMethod {
|
||||||
|
|
||||||
HHD,
|
HHD,
|
||||||
|
|
|
@ -38,8 +38,8 @@ open class Signaturkopf(
|
||||||
Sicherheitsprofil(
|
Sicherheitsprofil(
|
||||||
Sicherheitsverfahren.PIN_TAN_Verfahren,
|
Sicherheitsverfahren.PIN_TAN_Verfahren,
|
||||||
versionOfSecurityProcedure
|
versionOfSecurityProcedure
|
||||||
), // fints4k only supports Pin/Tan and PSD2 requires two step tan procedure; the only exception is the first dialog to get user's TAN procedures which allows to use one step tan procedure (as we don't know TAN procedures yet)
|
), // fints4k only supports Pin/Tan and PSD2 requires two step tan procedure; the only exception is the first dialog to get user's TAN methods which allows to use one step tan procedure (as we don't know TAN method yet)
|
||||||
SicherheitsfunktionKodiert(bank.selectedTanProcedure.securityFunction),
|
SicherheitsfunktionKodiert(bank.selectedTanMethod.securityFunction),
|
||||||
Sicherheitskontrollreferenz(securityControlReference), // allowed: <>0
|
Sicherheitskontrollreferenz(securityControlReference), // allowed: <>0
|
||||||
BereichDerSicherheitsapplikationKodiert(BereichDerSicherheitsapplikation.SignaturkopfUndHBCINutzdaten), // allowed: 1 ?
|
BereichDerSicherheitsapplikationKodiert(BereichDerSicherheitsapplikation.SignaturkopfUndHBCINutzdaten), // allowed: 1 ?
|
||||||
RolleDesSicherheitslieferantenKodiert(), // allowed: 1
|
RolleDesSicherheitslieferantenKodiert(), // allowed: 1
|
||||||
|
|
|
@ -24,19 +24,19 @@ open class AccountData(
|
||||||
internal constructor() : this("", null, Laenderkennzeichen.Germany, "", null, "", null, null, "", null, null, listOf()) // for object deserializers
|
internal constructor() : this("", null, Laenderkennzeichen.Germany, "", null, "", null, null, "", null, null, listOf()) // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
protected open val supportedFeatures = mutableSetOf<AccountFeature>()
|
protected open val _supportedFeatures = mutableSetOf<AccountFeature>()
|
||||||
|
|
||||||
|
|
||||||
open fun supportsFeature(feature: AccountFeature): Boolean {
|
open fun supportsFeature(feature: AccountFeature): Boolean {
|
||||||
return supportedFeatures.contains(feature)
|
return _supportedFeatures.contains(feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setSupportsFeature(feature: AccountFeature, isSupported: Boolean) {
|
open fun setSupportsFeature(feature: AccountFeature, isSupported: Boolean) {
|
||||||
if (isSupported) {
|
if (isSupported) {
|
||||||
supportedFeatures.add(feature)
|
_supportedFeatures.add(feature)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
supportedFeatures.remove(feature)
|
_supportedFeatures.remove(feature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ open class BankData(
|
||||||
open var customerName: String = "",
|
open var customerName: String = "",
|
||||||
open var updVersion: Int = UPDVersion.VersionNotReceivedYet,
|
open var updVersion: Int = UPDVersion.VersionNotReceivedYet,
|
||||||
|
|
||||||
open var tanProceduresSupportedByBank: List<TanProcedure> = listOf(),
|
open var tanMethodSupportedByBank: List<TanMethod> = listOf(),
|
||||||
open var tanProceduresAvailableForUser: List<TanProcedure> = listOf(),
|
open var tanMethodsAvailableForUser: List<TanMethod> = listOf(),
|
||||||
open var selectedTanProcedure: TanProcedure = TanProcedureNotSelected,
|
open var selectedTanMethod: TanMethod = TanMethodNotSelected,
|
||||||
open var tanMedia: List<TanMedium> = listOf(),
|
open var tanMedia: List<TanMedium> = listOf(),
|
||||||
open var changeTanMediumParameters: ChangeTanMediaParameters? = null,
|
open var changeTanMediumParameters: ChangeTanMediaParameters? = null,
|
||||||
open var pinInfo: PinInfo? = null,
|
open var pinInfo: PinInfo? = null,
|
||||||
|
@ -51,7 +51,7 @@ open class BankData(
|
||||||
companion object {
|
companion object {
|
||||||
val SecurityFunctionNotSelected = Sicherheitsfunktion.Einschritt_Verfahren
|
val SecurityFunctionNotSelected = Sicherheitsfunktion.Einschritt_Verfahren
|
||||||
|
|
||||||
val TanProcedureNotSelected = TanProcedure("NOT_SELECTED", SecurityFunctionNotSelected, TanProcedureType.EnterTan)
|
val TanMethodNotSelected = TanMethod("NOT_SELECTED", SecurityFunctionNotSelected, TanMethodType.EnterTan)
|
||||||
|
|
||||||
// TODO: is the BIC really needed at anonymous dialog init?
|
// TODO: is the BIC really needed at anonymous dialog init?
|
||||||
fun anonymous(bankCode: String, finTs3ServerAddress: String, bic: String): BankData {
|
fun anonymous(bankCode: String, finTs3ServerAddress: String, bic: String): BankData {
|
||||||
|
@ -70,8 +70,8 @@ open class BankData(
|
||||||
get() = ArrayList(_accounts)
|
get() = ArrayList(_accounts)
|
||||||
|
|
||||||
|
|
||||||
open val isTanProcedureSelected: Boolean
|
open val isTanMethodSelected: Boolean
|
||||||
get() = selectedTanProcedure != TanProcedureNotSelected
|
get() = selectedTanMethod != TanMethodNotSelected
|
||||||
|
|
||||||
|
|
||||||
open fun addAccount(account: AccountData) {
|
open fun addAccount(account: AccountData) {
|
||||||
|
@ -105,8 +105,8 @@ open class BankData(
|
||||||
updVersion = UPDVersion.VersionNotReceivedYet
|
updVersion = UPDVersion.VersionNotReceivedYet
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun resetSelectedTanProcedure() {
|
open fun resetSelectedTanMethod() {
|
||||||
selectedTanProcedure = TanProcedureNotSelected
|
selectedTanMethod = TanMethodNotSelected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ open class DialogContext(
|
||||||
var dialogId: String = InitialDialogId,
|
var dialogId: String = InitialDialogId,
|
||||||
var response: BankResponse? = null,
|
var response: BankResponse? = null,
|
||||||
var didBankCloseDialog: Boolean = false,
|
var didBankCloseDialog: Boolean = false,
|
||||||
versionOfSecurityProcedure: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.Version_2,
|
versionOfSecurityMethod: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.Version_2,
|
||||||
var previousMessageInDialog: MessageBuilderResult? = null, // for PinTan almost always the case except for getting a user's TAN procedures
|
var previousMessageInDialog: MessageBuilderResult? = null, // for PinTan almost always the case except for getting a user's TAN methods
|
||||||
var chunkedResponseHandler: ((BankResponse) -> Unit)? = null
|
var chunkedResponseHandler: ((BankResponse) -> Unit)? = null
|
||||||
) : MessageBaseData(bank, product, versionOfSecurityProcedure) {
|
) : MessageBaseData(bank, product, versionOfSecurityMethod) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val InitialDialogId = "0"
|
const val InitialDialogId = "0"
|
||||||
|
|
|
@ -6,7 +6,7 @@ import net.dankito.banking.fints.response.client.FinTsClientResponse
|
||||||
|
|
||||||
open class EnterTanResult protected constructor(
|
open class EnterTanResult protected constructor(
|
||||||
val enteredTan: String?,
|
val enteredTan: String?,
|
||||||
val changeTanProcedureTo: TanProcedure? = null,
|
val changeTanMethodTo: TanMethod? = null,
|
||||||
val changeTanMediumTo: TanMedium? = null,
|
val changeTanMediumTo: TanMedium? = null,
|
||||||
val changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)? = null
|
val changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
@ -21,8 +21,8 @@ open class EnterTanResult protected constructor(
|
||||||
return EnterTanResult(null)
|
return EnterTanResult(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun userAsksToChangeTanProcedure(changeTanProcedureTo: TanProcedure): EnterTanResult {
|
fun userAsksToChangeTanMethod(changeTanMethodTo: TanMethod): EnterTanResult {
|
||||||
return EnterTanResult(null, changeTanProcedureTo)
|
return EnterTanResult(null, changeTanMethodTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): EnterTanResult {
|
fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): EnterTanResult {
|
||||||
|
@ -32,8 +32,8 @@ open class EnterTanResult protected constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
if (changeTanProcedureTo != null) {
|
if (changeTanMethodTo != null) {
|
||||||
return "User asks to change TAN procedure to $changeTanProcedureTo"
|
return "User asks to change TAN method to $changeTanMethodTo"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changeTanMediumTo != null) {
|
if (changeTanMediumTo != null) {
|
||||||
|
|
|
@ -7,12 +7,12 @@ open class FlickerCodeTanChallenge(
|
||||||
val flickerCode: FlickerCode,
|
val flickerCode: FlickerCode,
|
||||||
messageToShowToUser: String,
|
messageToShowToUser: String,
|
||||||
challenge: String,
|
challenge: String,
|
||||||
tanProcedure: TanProcedure,
|
tanMethod: TanMethod,
|
||||||
tanMediaIdentifier: String?
|
tanMediaIdentifier: String?
|
||||||
) : TanChallenge(messageToShowToUser, challenge, tanProcedure, tanMediaIdentifier) {
|
) : TanChallenge(messageToShowToUser, challenge, tanMethod, tanMediaIdentifier) {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$tanProcedure (medium: $tanMediaIdentifier) $flickerCode: $messageToShowToUser"
|
return "$tanMethod (medium: $tanMediaIdentifier) $flickerCode: $messageToShowToUser"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,12 +7,12 @@ open class ImageTanChallenge(
|
||||||
val image: TanImage,
|
val image: TanImage,
|
||||||
messageToShowToUser: String,
|
messageToShowToUser: String,
|
||||||
challenge: String,
|
challenge: String,
|
||||||
tanProcedure: TanProcedure,
|
tanMethod: TanMethod,
|
||||||
tanMediaIdentifier: String?
|
tanMediaIdentifier: String?
|
||||||
) : TanChallenge(messageToShowToUser, challenge, tanProcedure, tanMediaIdentifier) {
|
) : TanChallenge(messageToShowToUser, challenge, tanMethod, tanMediaIdentifier) {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$tanProcedure (medium: $tanMediaIdentifier) $image: $messageToShowToUser"
|
return "$tanMethod (medium: $tanMediaIdentifier) $image: $messageToShowToUser"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,12 +4,12 @@ package net.dankito.banking.fints.model
|
||||||
open class TanChallenge(
|
open class TanChallenge(
|
||||||
val messageToShowToUser: String,
|
val messageToShowToUser: String,
|
||||||
val challenge: String,
|
val challenge: String,
|
||||||
val tanProcedure: TanProcedure,
|
val tanMethod: TanMethod,
|
||||||
val tanMediaIdentifier: String?
|
val tanMediaIdentifier: String?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$tanProcedure (medium: $tanMediaIdentifier): $messageToShowToUser"
|
return "$tanMethod (medium: $tanMediaIdentifier): $messageToShowToUser"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,10 +4,10 @@ import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.
|
||||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.AllowedTanFormat
|
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.AllowedTanFormat
|
||||||
|
|
||||||
|
|
||||||
open class TanProcedure(
|
open class TanMethod(
|
||||||
open val displayName: String,
|
open val displayName: String,
|
||||||
open val securityFunction: Sicherheitsfunktion,
|
open val securityFunction: Sicherheitsfunktion,
|
||||||
open val type: TanProcedureType,
|
open val type: TanMethodType,
|
||||||
open val hhdVersion: HHDVersion? = null,
|
open val hhdVersion: HHDVersion? = null,
|
||||||
open val maxTanInputLength: Int? = null,
|
open val maxTanInputLength: Int? = null,
|
||||||
open val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric,
|
open val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric,
|
||||||
|
@ -15,13 +15,13 @@ open class TanProcedure(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
internal constructor() : this("", Sicherheitsfunktion.Einschritt_Verfahren, TanProcedureType.EnterTan) // for object deserializers
|
internal constructor() : this("", Sicherheitsfunktion.Einschritt_Verfahren, TanMethodType.EnterTan) // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is TanProcedure) return false
|
if (other !is TanMethod) return false
|
||||||
|
|
||||||
if (displayName != other.displayName) return false
|
if (displayName != other.displayName) return false
|
||||||
if (securityFunction != other.securityFunction) return false
|
if (securityFunction != other.securityFunction) return false
|
|
@ -1,7 +1,7 @@
|
||||||
package net.dankito.banking.fints.model
|
package net.dankito.banking.fints.model
|
||||||
|
|
||||||
|
|
||||||
enum class TanProcedureType {
|
enum class TanMethodType {
|
||||||
|
|
||||||
EnterTan,
|
EnterTan,
|
||||||
|
|
|
@ -17,7 +17,7 @@ open class BankResponse(
|
||||||
* When a serious error occurred during web request or response parsing.
|
* When a serious error occurred during web request or response parsing.
|
||||||
*/
|
*/
|
||||||
val errorMessage: String? = null,
|
val errorMessage: String? = null,
|
||||||
val noTanProcedureSelected: Boolean = false,
|
val noTanMethodSelected: Boolean = false,
|
||||||
val messageCreationError: MessageBuilderResult? = null
|
val messageCreationError: MessageBuilderResult? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ open class BankResponse(
|
||||||
open var tanRequiredButWeWereToldToAbortIfSo = false
|
open var tanRequiredButWeWereToldToAbortIfSo = false
|
||||||
|
|
||||||
open val successful: Boolean
|
open val successful: Boolean
|
||||||
get() = noTanProcedureSelected == false && couldCreateMessage && didReceiveResponse
|
get() = noTanMethodSelected == false && couldCreateMessage && didReceiveResponse
|
||||||
&& responseContainsErrors == false && tanRequiredButUserDidNotEnterOne == false
|
&& responseContainsErrors == false && tanRequiredButUserDidNotEnterOne == false
|
||||||
&& tanRequiredButWeWereToldToAbortIfSo == false
|
&& tanRequiredButWeWereToldToAbortIfSo == false
|
||||||
|
|
||||||
|
@ -89,10 +89,10 @@ open class BankResponse(
|
||||||
open val supportedJobs: List<JobParameters>
|
open val supportedJobs: List<JobParameters>
|
||||||
get() = receivedSegments.mapNotNull { it as? JobParameters }
|
get() = receivedSegments.mapNotNull { it as? JobParameters }
|
||||||
|
|
||||||
open val supportedTanProceduresForUser: List<Sicherheitsfunktion>
|
open val supportedTanMethodsForUser: List<Sicherheitsfunktion>
|
||||||
get() = segmentFeedbacks.flatMap { it.feedbacks }
|
get() = segmentFeedbacks.flatMap { it.feedbacks }
|
||||||
.filterIsInstance<SupportedTanProceduresForUserFeedback>()
|
.filterIsInstance<SupportedTanMethodsForUserFeedback>()
|
||||||
.flatMap { it.supportedTanProcedures }
|
.flatMap { it.supportedTanMethods }
|
||||||
|
|
||||||
|
|
||||||
open fun <T : ReceivedSegment> getFirstSegmentById(id: ISegmentId): T? {
|
open fun <T : ReceivedSegment> getFirstSegmentById(id: ISegmentId): T? {
|
||||||
|
|
|
@ -33,7 +33,7 @@ open class ResponseParser(
|
||||||
|
|
||||||
const val AufsetzpunktResponseCode = 3040
|
const val AufsetzpunktResponseCode = 3040
|
||||||
|
|
||||||
const val SupportedTanProceduresForUserResponseCode = 3920
|
const val SupportedTanMethodsForUserResponseCode = 3920
|
||||||
|
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(ResponseParser::class)
|
private val log = LoggerFactory.getLogger(ResponseParser::class)
|
||||||
|
@ -155,9 +155,9 @@ open class ResponseParser(
|
||||||
val referencedDataElement = parseStringToNullIfEmpty(dataElements[1])
|
val referencedDataElement = parseStringToNullIfEmpty(dataElements[1])
|
||||||
val message = parseString(dataElements[2])
|
val message = parseString(dataElements[2])
|
||||||
|
|
||||||
if (responseCode == SupportedTanProceduresForUserResponseCode) {
|
if (responseCode == SupportedTanMethodsForUserResponseCode) {
|
||||||
val supportedProcedures = parseCodeEnum(dataElements.subList(3, dataElements.size), Sicherheitsfunktion.values())
|
val supportedMethods = parseCodeEnum(dataElements.subList(3, dataElements.size), Sicherheitsfunktion.values())
|
||||||
return SupportedTanProceduresForUserFeedback(supportedProcedures, message)
|
return SupportedTanMethodsForUserFeedback(supportedMethods, message)
|
||||||
}
|
}
|
||||||
else if (responseCode == AufsetzpunktResponseCode) {
|
else if (responseCode == AufsetzpunktResponseCode) {
|
||||||
return AufsetzpunktFeedback(parseString(dataElements[3]), message)
|
return AufsetzpunktFeedback(parseString(dataElements[3]), message)
|
||||||
|
@ -375,81 +375,81 @@ open class ResponseParser(
|
||||||
val proceduresDataElements = dataElements.subList(3, dataElements.size)
|
val proceduresDataElements = dataElements.subList(3, dataElements.size)
|
||||||
|
|
||||||
return TwoStepTanProcedureParameters(oneStepProcedureAllowed, moreThanOneTanDependentJobPerMessageAllowed,
|
return TwoStepTanProcedureParameters(oneStepProcedureAllowed, moreThanOneTanDependentJobPerMessageAllowed,
|
||||||
jobHashValue, mapToTanProcedureParameters(proceduresDataElements))
|
jobHashValue, mapToTanMethodParameters(proceduresDataElements))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapToTanProcedureParameters(proceduresDataElements: List<String>): List<TanProcedureParameters> {
|
protected open fun mapToTanMethodParameters(methodsDataElements: List<String>): List<TanMethodParameters> {
|
||||||
// TODO: this throws an error for HITANS in version 4, but PSD2 needs HKTAN at least in version 6 anyway
|
// TODO: this throws an error for HITANS in version 4, but PSD2 needs HKTAN at least in version 6 anyway
|
||||||
|
|
||||||
val parsedProceduresParameters = mutableListOf<TanProcedureParameters>()
|
val parsedMethodsParameters = mutableListOf<TanMethodParameters>()
|
||||||
var remainingDataElements = proceduresDataElements
|
var remainingDataElements = methodsDataElements
|
||||||
|
|
||||||
while (remainingDataElements.size >= 20) { // parameters have at least 20 data elements, the last element is optional
|
while (remainingDataElements.size >= 20) { // parameters have at least 20 data elements, the last element is optional
|
||||||
val dataElementForNextProcedure = if (remainingDataElements.size >= 21) remainingDataElements.subList(0, 21)
|
val dataElementForNextMethod = if (remainingDataElements.size >= 21) remainingDataElements.subList(0, 21)
|
||||||
else remainingDataElements.subList(0, 20)
|
else remainingDataElements.subList(0, 20)
|
||||||
|
|
||||||
val procedureParameters = mapToSingleTanProcedureParameters(dataElementForNextProcedure)
|
val methodParameters = mapToSingleTanMethodParameters(dataElementForNextMethod)
|
||||||
parsedProceduresParameters.add(procedureParameters)
|
parsedMethodsParameters.add(methodParameters)
|
||||||
|
|
||||||
val has21ElementsParsed = procedureParameters.countSupportedActiveTanMedia != null ||
|
val has21ElementsParsed = methodParameters.countSupportedActiveTanMedia != null ||
|
||||||
(dataElementForNextProcedure.size >= 21 && dataElementForNextProcedure[20].isBlank())
|
(dataElementForNextMethod.size >= 21 && dataElementForNextMethod[20].isBlank())
|
||||||
|
|
||||||
if (has21ElementsParsed) remainingDataElements = remainingDataElements.subList(21, remainingDataElements.size)
|
if (has21ElementsParsed) remainingDataElements = remainingDataElements.subList(21, remainingDataElements.size)
|
||||||
else remainingDataElements = remainingDataElements.subList(20, remainingDataElements.size)
|
else remainingDataElements = remainingDataElements.subList(20, remainingDataElements.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedProceduresParameters
|
return parsedMethodsParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mapToSingleTanProcedureParameters(procedureDataElements: List<String>): TanProcedureParameters {
|
protected open fun mapToSingleTanMethodParameters(methodDataElements: List<String>): TanMethodParameters {
|
||||||
|
|
||||||
return TanProcedureParameters(
|
return TanMethodParameters(
|
||||||
parseCodeEnum(procedureDataElements[0], Sicherheitsfunktion.values()),
|
parseCodeEnum(methodDataElements[0], Sicherheitsfunktion.values()),
|
||||||
parseCodeEnum(procedureDataElements[1], TanProcess.values()),
|
parseCodeEnum(methodDataElements[1], TanProcess.values()),
|
||||||
parseString(procedureDataElements[2]),
|
parseString(methodDataElements[2]),
|
||||||
tryToParseZkaTanProcedure(procedureDataElements[3]),
|
tryToParseZkaTanMethod(methodDataElements[3]),
|
||||||
parseStringToNullIfEmpty(procedureDataElements[4]),
|
parseStringToNullIfEmpty(methodDataElements[4]),
|
||||||
parseString(procedureDataElements[5]),
|
parseString(methodDataElements[5]),
|
||||||
parseInt(procedureDataElements[6]),
|
parseInt(methodDataElements[6]),
|
||||||
parseCodeEnum(procedureDataElements[7], AllowedTanFormat.values()),
|
parseCodeEnum(methodDataElements[7], AllowedTanFormat.values()),
|
||||||
parseString(procedureDataElements[8]),
|
parseString(methodDataElements[8]),
|
||||||
parseInt(procedureDataElements[9]),
|
parseInt(methodDataElements[9]),
|
||||||
// for HITANS 4 and 5 here is another "Anzahl unterstützter aktiver TAN-Listen" Integer element
|
// for HITANS 4 and 5 here is another "Anzahl unterstützter aktiver TAN-Listen" Integer element
|
||||||
parseBoolean(procedureDataElements[10]),
|
parseBoolean(methodDataElements[10]),
|
||||||
parseCodeEnum(procedureDataElements[11], TanZeitUndDialogbezug.values()),
|
parseCodeEnum(methodDataElements[11], TanZeitUndDialogbezug.values()),
|
||||||
// for HITANS 4 and 5 here is another "TAN-Listennummer erforderlich" code element
|
// for HITANS 4 and 5 here is another "TAN-Listennummer erforderlich" code element
|
||||||
parseBoolean(procedureDataElements[12]),
|
parseBoolean(methodDataElements[12]),
|
||||||
tryToParseSmsAbbuchungskontoErforderlich(procedureDataElements[13]),
|
tryToParseSmsAbbuchungskontoErforderlich(methodDataElements[13]),
|
||||||
tryToParseAuftraggeberkontoErforderlich(procedureDataElements[14]),
|
tryToParseAuftraggeberkontoErforderlich(methodDataElements[14]),
|
||||||
parseBoolean(procedureDataElements[15]),
|
parseBoolean(methodDataElements[15]),
|
||||||
parseBoolean(procedureDataElements[16]),
|
parseBoolean(methodDataElements[16]),
|
||||||
parseCodeEnum(procedureDataElements[17], Initialisierungsmodus.values()),
|
parseCodeEnum(methodDataElements[17], Initialisierungsmodus.values()),
|
||||||
parseCodeEnum(procedureDataElements[18], BezeichnungDesTanMediumsErforderlich.values()),
|
parseCodeEnum(methodDataElements[18], BezeichnungDesTanMediumsErforderlich.values()),
|
||||||
parseBoolean(procedureDataElements[19]),
|
parseBoolean(methodDataElements[19]),
|
||||||
if (procedureDataElements.size > 20) parseNullableInt(procedureDataElements[20]) else null
|
if (methodDataElements.size > 20) parseNullableInt(methodDataElements[20]) else null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun tryToParseZkaTanProcedure(mayZkaTanProcedure: String): ZkaTanProcedure? {
|
protected open fun tryToParseZkaTanMethod(mayZkaTanMethod: String): ZkaTanMethod? {
|
||||||
if (mayZkaTanProcedure.isBlank()) {
|
if (mayZkaTanMethod.isBlank()) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val lowerCaseMayZkaTanProcedure = mayZkaTanProcedure.toLowerCase()
|
val lowerCaseMayZkaTanMethod = mayZkaTanMethod.toLowerCase()
|
||||||
|
|
||||||
if (lowerCaseMayZkaTanProcedure == "mobiletan" || lowerCaseMayZkaTanProcedure == "mtan") {
|
if (lowerCaseMayZkaTanMethod == "mobiletan" || lowerCaseMayZkaTanMethod == "mtan") {
|
||||||
return ZkaTanProcedure.mobileTAN
|
return ZkaTanMethod.mobileTAN
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lowerCaseMayZkaTanProcedure == "apptan" || lowerCaseMayZkaTanProcedure == "phototan") {
|
if (lowerCaseMayZkaTanMethod == "apptan" || lowerCaseMayZkaTanMethod == "phototan") {
|
||||||
return ZkaTanProcedure.appTAN
|
return ZkaTanMethod.appTAN
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: what about these values, all returned by banks in anonymous dialog initialization:
|
// TODO: what about these values, all returned by banks in anonymous dialog initialization:
|
||||||
// BestSign, HHDUSB1, Secoder_UC, ZkaTANMode, photoTAN, QRTAN, 1822TAN+
|
// BestSign, HHDUSB1, Secoder_UC, ZkaTANMode, photoTAN, QRTAN, 1822TAN+
|
||||||
|
|
||||||
return ZkaTanProcedure.valueOf(mayZkaTanProcedure)
|
return ZkaTanMethod.valueOf(mayZkaTanMethod)
|
||||||
} catch (ignored: Exception) { }
|
} catch (ignored: Exception) { }
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -8,7 +8,7 @@ open class FinTsClientResponse(
|
||||||
|
|
||||||
open val successful: Boolean,
|
open val successful: Boolean,
|
||||||
|
|
||||||
open val noTanProcedureSelected: Boolean,
|
open val noTanMethodSelected: Boolean,
|
||||||
|
|
||||||
open val isStrongAuthenticationRequired: Boolean,
|
open val isStrongAuthenticationRequired: Boolean,
|
||||||
open val tanRequired: TanResponse? = null,
|
open val tanRequired: TanResponse? = null,
|
||||||
|
@ -31,7 +31,7 @@ open class FinTsClientResponse(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
||||||
constructor(response: BankResponse) : this(response.successful, response.noTanProcedureSelected,
|
constructor(response: BankResponse) : this(response.successful, response.noTanMethodSelected,
|
||||||
response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser,
|
response.isStrongAuthenticationRequired, response.tanResponse, response.errorsToShowToUser,
|
||||||
response.errorMessage, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
|
response.errorMessage, response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
|
||||||
response.messageCreationError?.isJobAllowed ?: true,
|
response.messageCreationError?.isJobAllowed ?: true,
|
||||||
|
@ -41,8 +41,8 @@ open class FinTsClientResponse(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
if (noTanProcedureSelected) {
|
if (noTanMethodSelected) {
|
||||||
return "Error: No TAN procedure selected"
|
return "Error: No TAN method selected"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isJobAllowed == false) {
|
if (isJobAllowed == false) {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package net.dankito.banking.fints.response.client
|
||||||
|
|
||||||
|
import net.dankito.banking.fints.response.BankResponse
|
||||||
|
import net.dankito.banking.fints.response.ResponseParser
|
||||||
|
|
||||||
|
|
||||||
|
open class GetUserTanMethodsResponse(bankResponse: BankResponse)
|
||||||
|
: BankResponse(bankResponse.didReceiveResponse, bankResponse.receivedResponse, bankResponse.receivedSegments,
|
||||||
|
bankResponse.errorMessage, bankResponse.noTanMethodSelected, bankResponse.messageCreationError) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* comdirect sends "9955::Unzulässiges TAN-Verfahren." even though '999' is a valid TAN method
|
||||||
|
* for init dialog if user's TAN methods are not known yet and it contains a '3920:' feedback with user's TAN methods
|
||||||
|
* -> if it contains a '3920:' feedback with user's TAN methods, then it's still a success.
|
||||||
|
*/
|
||||||
|
override val successful: Boolean
|
||||||
|
get() = noTanMethodSelected == false && couldCreateMessage && didReceiveResponse
|
||||||
|
&& tanRequiredButUserDidNotEnterOne == false
|
||||||
|
&& (responseContainsErrors == false || containsUsersTanMethodsFeedback())
|
||||||
|
|
||||||
|
protected open fun containsUsersTanMethodsFeedback(): Boolean {
|
||||||
|
val usersSupportedTanMethodsFeedback = segmentFeedbacks.flatMap { it.feedbacks }
|
||||||
|
.firstOrNull { it.responseCode == ResponseParser.SupportedTanMethodsForUserResponseCode }
|
||||||
|
|
||||||
|
return usersSupportedTanMethodsFeedback != null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
package net.dankito.banking.fints.response.client
|
|
||||||
|
|
||||||
import net.dankito.banking.fints.response.BankResponse
|
|
||||||
import net.dankito.banking.fints.response.ResponseParser
|
|
||||||
|
|
||||||
|
|
||||||
open class GetUserTanProceduresResponse(bankResponse: BankResponse)
|
|
||||||
: BankResponse(bankResponse.didReceiveResponse, bankResponse.receivedResponse, bankResponse.receivedSegments,
|
|
||||||
bankResponse.errorMessage, bankResponse.noTanProcedureSelected, bankResponse.messageCreationError) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* comdirect sends "9955::Unzulässiges TAN-Verfahren." even though '999' is a valid TAN procedure
|
|
||||||
* for init dialog if user's TAN procedures are not known yet and it contains a '3920:' feedback with user's TAN procedures
|
|
||||||
* -> if it contains a '3920:' feedback with user's TAN procedures, then it's still a success.
|
|
||||||
*/
|
|
||||||
override val successful: Boolean
|
|
||||||
get() = noTanProcedureSelected == false && couldCreateMessage && didReceiveResponse
|
|
||||||
&& tanRequiredButUserDidNotEnterOne == false
|
|
||||||
&& (responseContainsErrors == false || containsUsersTanProceduresFeedback())
|
|
||||||
|
|
||||||
protected open fun containsUsersTanProceduresFeedback(): Boolean {
|
|
||||||
val usersSupportedTanProceduresFeedback = segmentFeedbacks.flatMap { it.feedbacks }
|
|
||||||
.firstOrNull { it.responseCode == ResponseParser.SupportedTanProceduresForUserResponseCode }
|
|
||||||
|
|
||||||
return usersSupportedTanProceduresFeedback != null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,8 +3,8 @@ package net.dankito.banking.fints.response.segments
|
||||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||||
import net.dankito.banking.fints.response.ResponseParser
|
import net.dankito.banking.fints.response.ResponseParser
|
||||||
|
|
||||||
open class SupportedTanProceduresForUserFeedback(
|
open class SupportedTanMethodsForUserFeedback(
|
||||||
val supportedTanProcedures: List<Sicherheitsfunktion>,
|
val supportedTanMethods: List<Sicherheitsfunktion>,
|
||||||
message: String
|
message: String
|
||||||
)
|
)
|
||||||
: Feedback(ResponseParser.SupportedTanProceduresForUserResponseCode, message)
|
: Feedback(ResponseParser.SupportedTanMethodsForUserResponseCode, message)
|
|
@ -4,13 +4,13 @@ import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.
|
||||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
|
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||||
|
|
||||||
|
|
||||||
open class TanProcedureParameters(
|
open class TanMethodParameters(
|
||||||
val securityFunction: Sicherheitsfunktion,
|
val securityFunction: Sicherheitsfunktion,
|
||||||
val tanProcess: TanProcess,
|
val tanProcess: TanProcess,
|
||||||
val technicalTanProcedureIdentification: String,
|
val technicalTanMethodIdentification: String,
|
||||||
val zkaTanProcedure: ZkaTanProcedure?,
|
val zkaTanMethod: ZkaTanMethod?,
|
||||||
val versionZkaTanProcedure: String?,
|
val versionZkaTanMethod: String?,
|
||||||
val procedureName: String,
|
val methodName: String,
|
||||||
val maxTanInputLength: Int,
|
val maxTanInputLength: Int,
|
||||||
val allowedTanFormat: AllowedTanFormat,
|
val allowedTanFormat: AllowedTanFormat,
|
||||||
val descriptionToShowToUser: String,
|
val descriptionToShowToUser: String,
|
||||||
|
@ -35,7 +35,7 @@ open class TanProcedureParameters(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$procedureName $technicalTanProcedureIdentification"
|
return "$methodName $technicalTanMethodIdentification"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ open class TwoStepTanProcedureParameters(
|
||||||
val oneStepProcedureAllowed: Boolean,
|
val oneStepProcedureAllowed: Boolean,
|
||||||
val moreThanOneTanDependentJobPerMessageAllowed: Boolean,
|
val moreThanOneTanDependentJobPerMessageAllowed: Boolean,
|
||||||
val jobHashValue: String, // not evaluated for PIN/TAN
|
val jobHashValue: String, // not evaluated for PIN/TAN
|
||||||
val procedureParameters: List<TanProcedureParameters>
|
val methodParameters: List<TanMethodParameters>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
internal constructor() : this(false, false, "", listOf()) // for object deserializers
|
internal constructor() : this(false, false, "", listOf()) // for object deserializers
|
||||||
|
|
|
@ -36,7 +36,7 @@ abstract class FinTsTestBase {
|
||||||
|
|
||||||
const val ControlReference = "4477"
|
const val ControlReference = "4477"
|
||||||
|
|
||||||
val Bank = BankData(BankCode, CustomerId, Pin, BankFinTsServerAddress, Bic, "", BankCountryCode, selectedTanProcedure = TanProcedure("chipTAN-optisch", SecurityFunction, TanProcedureType.ChipTanFlickercode), selectedLanguage = Language)
|
val Bank = BankData(BankCode, CustomerId, Pin, BankFinTsServerAddress, Bic, "", BankCountryCode, selectedTanMethod = TanMethod("chipTAN-optisch", SecurityFunction, TanMethodType.ChipTanFlickercode), selectedLanguage = Language)
|
||||||
|
|
||||||
val Currency = "EUR"
|
val Currency = "EUR"
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun parseSegmentFeedback_AllowedUserTanProcedures() {
|
fun parseSegmentFeedback_AllowedUserTanMethods() {
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val result = underTest.parse("HIRMS:4:2:4+3050::BPD nicht mehr aktuell, aktuelle Version enthalten.+3920::Zugelassene Zwei-Schritt-Verfahren für den Benutzer.:910:911:912:913+0020::Der Auftrag wurde ausgeführt.")
|
val result = underTest.parse("HIRMS:4:2:4+3050::BPD nicht mehr aktuell, aktuelle Version enthalten.+3920::Zugelassene Zwei-Schritt-Verfahren für den Benutzer.:910:911:912:913+0020::Der Auftrag wurde ausgeführt.")
|
||||||
|
@ -256,7 +256,7 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
|
|
||||||
expect(result.segmentFeedbacks).hasSize(1)
|
expect(result.segmentFeedbacks).hasSize(1)
|
||||||
|
|
||||||
expect(result.supportedTanProceduresForUser).containsExactly(Sicherheitsfunktion.PIN_TAN_910,
|
expect(result.supportedTanMethodsForUser).containsExactly(Sicherheitsfunktion.PIN_TAN_910,
|
||||||
Sicherheitsfunktion.PIN_TAN_911, Sicherheitsfunktion.PIN_TAN_912, Sicherheitsfunktion.PIN_TAN_913)
|
Sicherheitsfunktion.PIN_TAN_911, Sicherheitsfunktion.PIN_TAN_912, Sicherheitsfunktion.PIN_TAN_913)
|
||||||
|
|
||||||
val segmentFeedback = result.segmentFeedbacks.first()
|
val segmentFeedback = result.segmentFeedbacks.first()
|
||||||
|
@ -272,8 +272,8 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
expect(firstFeedback.parameter).toBe(null)
|
expect(firstFeedback.parameter).toBe(null)
|
||||||
|
|
||||||
val secondFeedback = segmentFeedback.feedbacks[1]
|
val secondFeedback = segmentFeedback.feedbacks[1]
|
||||||
expect(secondFeedback is SupportedTanProceduresForUserFeedback).isTrue()
|
expect(secondFeedback is SupportedTanMethodsForUserFeedback).isTrue()
|
||||||
expect((secondFeedback as SupportedTanProceduresForUserFeedback).supportedTanProcedures)
|
expect((secondFeedback as SupportedTanMethodsForUserFeedback).supportedTanMethods)
|
||||||
.containsExactly(Sicherheitsfunktion.PIN_TAN_910,Sicherheitsfunktion.PIN_TAN_911,
|
.containsExactly(Sicherheitsfunktion.PIN_TAN_910,Sicherheitsfunktion.PIN_TAN_911,
|
||||||
Sicherheitsfunktion.PIN_TAN_912, Sicherheitsfunktion.PIN_TAN_913)
|
Sicherheitsfunktion.PIN_TAN_912, Sicherheitsfunktion.PIN_TAN_913)
|
||||||
expect(secondFeedback.responseCode).toBe(3920)
|
expect(secondFeedback.responseCode).toBe(3920)
|
||||||
|
@ -726,8 +726,8 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
||||||
expect(segment.tanProcedureParameters.jobHashValue).toBe("0")
|
expect(segment.tanProcedureParameters.jobHashValue).toBe("0")
|
||||||
|
|
||||||
expect(segment.tanProcedureParameters.procedureParameters).hasSize(7)
|
expect(segment.tanProcedureParameters.methodParameters).hasSize(7)
|
||||||
expect(segment.tanProcedureParameters.procedureParameters.map { it.procedureName })
|
expect(segment.tanProcedureParameters.methodParameters.map { it.methodName })
|
||||||
.containsExactly("chipTAN manuell", "chipTAN optisch", "chipTAN-USB", "chipTAN-QR",
|
.containsExactly("chipTAN manuell", "chipTAN optisch", "chipTAN-USB", "chipTAN-QR",
|
||||||
"smsTAN", "pushTAN", "iTAN")
|
"smsTAN", "pushTAN", "iTAN")
|
||||||
}
|
}
|
||||||
|
@ -751,8 +751,8 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
||||||
expect(segment.tanProcedureParameters.jobHashValue).toBe("0")
|
expect(segment.tanProcedureParameters.jobHashValue).toBe("0")
|
||||||
|
|
||||||
expect(segment.tanProcedureParameters.procedureParameters).hasSize(2)
|
expect(segment.tanProcedureParameters.methodParameters).hasSize(2)
|
||||||
expect(segment.tanProcedureParameters.procedureParameters.map { it.procedureName })
|
expect(segment.tanProcedureParameters.methodParameters.map { it.methodName })
|
||||||
.containsExactly("mobileTAN-Verfahren", "photoTAN-Verfahren")
|
.containsExactly("mobileTAN-Verfahren", "photoTAN-Verfahren")
|
||||||
}
|
}
|
||||||
?: run { fail("No segment of type TanInfo found in ${result.receivedSegments}") }
|
?: run { fail("No segment of type TanInfo found in ${result.receivedSegments}") }
|
||||||
|
@ -775,8 +775,8 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
||||||
expect(segment.tanProcedureParameters.jobHashValue).toBe("0")
|
expect(segment.tanProcedureParameters.jobHashValue).toBe("0")
|
||||||
|
|
||||||
expect(segment.tanProcedureParameters.procedureParameters).hasSize(5)
|
expect(segment.tanProcedureParameters.methodParameters).hasSize(5)
|
||||||
expect(segment.tanProcedureParameters.procedureParameters.map { it.procedureName })
|
expect(segment.tanProcedureParameters.methodParameters.map { it.methodName })
|
||||||
.containsExactly("SMS-TAN", "chipTAN comfort", "chipTAN comfort manuell", "BV AppTAN", "PhotoTAN")
|
.containsExactly("SMS-TAN", "chipTAN comfort", "chipTAN comfort manuell", "BV AppTAN", "PhotoTAN")
|
||||||
}
|
}
|
||||||
?: run { fail("No segment of type TanInfo found in ${result.receivedSegments}") }
|
?: run { fail("No segment of type TanInfo found in ${result.receivedSegments}") }
|
||||||
|
@ -799,8 +799,8 @@ class ResponseParserTest : FinTsTestBase() {
|
||||||
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
expect(segment.tanProcedureParameters.moreThanOneTanDependentJobPerMessageAllowed).isFalse()
|
||||||
expect(segment.tanProcedureParameters.jobHashValue).toBe("1")
|
expect(segment.tanProcedureParameters.jobHashValue).toBe("1")
|
||||||
|
|
||||||
expect(segment.tanProcedureParameters.procedureParameters).hasSize(6)
|
expect(segment.tanProcedureParameters.methodParameters).hasSize(6)
|
||||||
expect(segment.tanProcedureParameters.procedureParameters.map { it.procedureName })
|
expect(segment.tanProcedureParameters.methodParameters.map { it.methodName })
|
||||||
.containsExactly("iTAN", "mobile TAN", "App-basiertes Verfahren", "chipTAN 1.4",
|
.containsExactly("iTAN", "mobile TAN", "App-basiertes Verfahren", "chipTAN 1.4",
|
||||||
"chipTAN 1.4 manuell", "Vorlagen und Informationen")
|
"chipTAN 1.4 manuell", "Vorlagen und Informationen")
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import net.dankito.banking.fints.model.CustomerData;
|
||||||
import net.dankito.banking.fints.model.EnterTanGeneratorAtcResult;
|
import net.dankito.banking.fints.model.EnterTanGeneratorAtcResult;
|
||||||
import net.dankito.banking.fints.model.EnterTanResult;
|
import net.dankito.banking.fints.model.EnterTanResult;
|
||||||
import net.dankito.banking.fints.model.TanChallenge;
|
import net.dankito.banking.fints.model.TanChallenge;
|
||||||
import net.dankito.banking.fints.model.TanProcedure;
|
import net.dankito.banking.fints.model.TanMethod;
|
||||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium;
|
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium;
|
||||||
import net.dankito.banking.fints.model.mapper.BankDataMapper;
|
import net.dankito.banking.fints.model.mapper.BankDataMapper;
|
||||||
import net.dankito.banking.fints.response.client.AddAccountResponse;
|
import net.dankito.banking.fints.response.client.AddAccountResponse;
|
||||||
|
@ -86,11 +86,11 @@ public class JavaShowcase {
|
||||||
FinTsClientCallback callback = new FinTsClientCallback() {
|
FinTsClientCallback callback = new FinTsClientCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TanProcedure askUserForTanProcedure(List<? extends TanProcedure> supportedTanProcedures, TanProcedure suggestedTanProcedure) {
|
public TanMethod askUserForTanMethod(List<? extends TanMethod> supportedTanMethods, TanMethod suggestedTanMethod) {
|
||||||
// E.g. show a dialog to ask for user's TAN procedure.
|
// E.g. show a dialog to ask for user's TAN method.
|
||||||
// In most cases it's senseful to simply return suggestedTanProcedure and to let
|
// In most cases it's senseful to simply return suggestedTanMethod and to let
|
||||||
// user select TAN procedure when entering TAN is required (see enterTan() below)
|
// user select TAN method when entering TAN is required (see enterTan() below)
|
||||||
return suggestedTanProcedure;
|
return suggestedTanMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,7 +103,7 @@ public class JavaShowcase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnterTanGeneratorAtcResult enterTanGeneratorAtc(CustomerData customer, TanGeneratorTanMedium tanMedium) {
|
public EnterTanGeneratorAtcResult enterTanGeneratorAtc(CustomerData customer, TanGeneratorTanMedium tanMedium) {
|
||||||
// needed only in rare cases to synchronize TAN generator for chipTAN procedures. E.g. show
|
// needed only in rare cases to synchronize TAN generator for chipTAN methods. E.g. show
|
||||||
// - Android: net.dankito.banking.ui.android.dialogs.EnterAtcDialog
|
// - Android: net.dankito.banking.ui.android.dialogs.EnterAtcDialog
|
||||||
return EnterTanGeneratorAtcResult.Companion.userDidNotEnterAtc(); // user did not enter TAN and ATC. aborts operation
|
return EnterTanGeneratorAtcResult.Companion.userDidNotEnterAtc(); // user did not enter TAN and ATC. aborts operation
|
||||||
}
|
}
|
|
@ -48,16 +48,16 @@ open class FinTsClientTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private var didAskUserForTanProcedure = false
|
private var didAskUserForTanMethod = false
|
||||||
|
|
||||||
private var didAskUserToEnterTan = false
|
private var didAskUserToEnterTan = false
|
||||||
|
|
||||||
|
|
||||||
private val callback = object : FinTsClientCallback {
|
private val callback = object : FinTsClientCallback {
|
||||||
|
|
||||||
override fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?, callback: (TanProcedure?) -> Unit) {
|
override fun askUserForTanMethod(supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
|
||||||
didAskUserForTanProcedure = true
|
didAskUserForTanMethod = true
|
||||||
callback(suggestedTanProcedure) // simply return suggestedTanProcedure as in most cases it's the best fitting one
|
callback(suggestedTanMethod) // simply return suggestedTanMethod as in most cases it's the best fitting one
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||||
|
@ -93,7 +93,7 @@ open class FinTsClientTestBase {
|
||||||
// then
|
// then
|
||||||
expect(result.successful).isTrue()
|
expect(result.successful).isTrue()
|
||||||
expect(BankDataAnonymous.supportedHbciVersions).isNotEmpty()
|
expect(BankDataAnonymous.supportedHbciVersions).isNotEmpty()
|
||||||
expect(BankDataAnonymous.tanProceduresSupportedByBank).isNotEmpty()
|
expect(BankDataAnonymous.tanMethodSupportedByBank).isNotEmpty()
|
||||||
expect(BankDataAnonymous.supportedJobs).isNotEmpty()
|
expect(BankDataAnonymous.supportedJobs).isNotEmpty()
|
||||||
expect(BankDataAnonymous.supportedLanguages).isNotEmpty()
|
expect(BankDataAnonymous.supportedLanguages).isNotEmpty()
|
||||||
expect(BankDataAnonymous.bankName).isNotEmpty()
|
expect(BankDataAnonymous.bankName).isNotEmpty()
|
||||||
|
@ -122,16 +122,16 @@ open class FinTsClientTestBase {
|
||||||
|
|
||||||
expect(result.successful).isTrue()
|
expect(result.successful).isTrue()
|
||||||
|
|
||||||
expect(didAskUserForTanProcedure).isFalse()
|
expect(didAskUserForTanMethod).isFalse()
|
||||||
|
|
||||||
expect(Bank.bankName).isNotEmpty()
|
expect(Bank.bankName).isNotEmpty()
|
||||||
expect(Bank.supportedJobs).isNotEmpty() // supported jobs are now known
|
expect(Bank.supportedJobs).isNotEmpty() // supported jobs are now known
|
||||||
expect(Bank.tanProceduresSupportedByBank).isNotEmpty() // supported tan procedures are now known
|
expect(Bank.tanMethodSupportedByBank).isNotEmpty() // supported tan methods are now known
|
||||||
expect(Bank.supportedHbciVersions).isNotEmpty() // supported HBIC versions are now known
|
expect(Bank.supportedHbciVersions).isNotEmpty() // supported HBIC versions are now known
|
||||||
expect(Bank.supportedLanguages).isNotEmpty() // supported languages are now known
|
expect(Bank.supportedLanguages).isNotEmpty() // supported languages are now known
|
||||||
|
|
||||||
expect(Bank.customerName).isNotEmpty()
|
expect(Bank.customerName).isNotEmpty()
|
||||||
expect(Bank.tanProceduresAvailableForUser).isNotEmpty()
|
expect(Bank.tanMethodsAvailableForUser).isNotEmpty()
|
||||||
expect(Bank.selectedLanguage).notToBe(Dialogsprache.Default) // language is set now
|
expect(Bank.selectedLanguage).notToBe(Dialogsprache.Default) // language is set now
|
||||||
expect(Bank.customerSystemId).notToBe(KundensystemStatus.SynchronizingCustomerSystemId.code) // customer system id is now set
|
expect(Bank.customerSystemId).notToBe(KundensystemStatus.SynchronizingCustomerSystemId.code) // customer system id is now set
|
||||||
expect(Bank.customerSystemStatus).toBe(KundensystemStatusWerte.Benoetigt) // customerSystemStatus is set now
|
expect(Bank.customerSystemStatus).toBe(KundensystemStatusWerte.Benoetigt) // customerSystemStatus is set now
|
||||||
|
@ -174,7 +174,7 @@ open class FinTsClientTestBase {
|
||||||
@Test
|
@Test
|
||||||
fun getTanMediaList() {
|
fun getTanMediaList() {
|
||||||
|
|
||||||
// this test is only senseful for accounts using chipTAN / TAN generator as TAN procedure
|
// this test is only senseful for accounts using chipTAN / TAN generator as TAN method
|
||||||
|
|
||||||
underTest.getAnonymousBankInfo(Bank) { }
|
underTest.getAnonymousBankInfo(Bank) { }
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import net.dankito.banking.bankfinder.BankInfo
|
||||||
import net.dankito.banking.fints.response.BankResponse
|
import net.dankito.banking.fints.response.BankResponse
|
||||||
import net.dankito.banking.fints.response.segments.SepaAccountInfoParameters
|
import net.dankito.banking.fints.response.segments.SepaAccountInfoParameters
|
||||||
import net.dankito.banking.fints.response.segments.TanInfo
|
import net.dankito.banking.fints.response.segments.TanInfo
|
||||||
import net.dankito.banking.fints.response.segments.TanProcedureParameters
|
import net.dankito.banking.fints.response.segments.TanMethodParameters
|
||||||
import net.dankito.banking.fints.util.*
|
import net.dankito.banking.fints.util.*
|
||||||
import net.dankito.banking.fints.webclient.KtorWebClient
|
import net.dankito.banking.fints.webclient.KtorWebClient
|
||||||
import org.apache.commons.csv.CSVFormat
|
import org.apache.commons.csv.CSVFormat
|
||||||
|
@ -59,19 +59,19 @@ class BanksFinTsDetailsRetriever {
|
||||||
super.updateBankData(bank, response)
|
super.updateBankData(bank, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mapToTanProcedureTypePublic(parameters: TanProcedureParameters): TanProcedureType? {
|
fun mapToTanMethodTypePublic(parameters: TanMethodParameters): TanMethodType? {
|
||||||
return super.mapToTanProcedureType(parameters)
|
return super.mapToTanMethodType(parameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val requestNotSuccessful = mutableListOf<BankInfo>()
|
private val requestNotSuccessful = mutableListOf<BankInfo>()
|
||||||
|
|
||||||
private val tanProcedureParameter = mutableMapOf<String, MutableSet<TanProcedureParameters>>()
|
private val tanMethodParameter = mutableMapOf<String, MutableSet<TanMethodParameters>>()
|
||||||
private val tanProcedureTypes = mutableMapOf<TanProcedureType?, MutableSet<TanProcedureParameters>>()
|
private val tanMethodTypes = mutableMapOf<TanMethodType?, MutableSet<TanMethodParameters>>()
|
||||||
|
|
||||||
private val tanProcedureParameterTechnicalIdentification = mutableSetOf<String>()
|
private val tanMethodParameterTechnicalIdentification = mutableSetOf<String>()
|
||||||
private val tanProcedureParameterVersionZkaTanProcedure = mutableSetOf<String?>()
|
private val tanMethodParameterVersionZkaTanMethod = mutableSetOf<String?>()
|
||||||
|
|
||||||
private val requiresSmsAbbuchungskonto = mutableListOf<BankInfo>()
|
private val requiresSmsAbbuchungskonto = mutableListOf<BankInfo>()
|
||||||
private val requiresAuftraggeberkonto = mutableListOf<BankInfo>()
|
private val requiresAuftraggeberkonto = mutableListOf<BankInfo>()
|
||||||
|
@ -167,10 +167,10 @@ class BanksFinTsDetailsRetriever {
|
||||||
val supportsHKCCS1 = supportsJobInVersion(bank, "HKCCS", 1)
|
val supportsHKCCS1 = supportsJobInVersion(bank, "HKCCS", 1)
|
||||||
|
|
||||||
val tanInfo = anonymousBankInfoResponse.receivedSegments.filterIsInstance(TanInfo::class.java)
|
val tanInfo = anonymousBankInfoResponse.receivedSegments.filterIsInstance(TanInfo::class.java)
|
||||||
val tanProcedureParameters = tanInfo.flatMap { it.tanProcedureParameters.procedureParameters }
|
val tanMethodParameters = tanInfo.flatMap { it.tanProcedureParameters.methodParameters }
|
||||||
val supportedTanProcedures = tanProcedureParameters.map { it.technicalTanProcedureIdentification }
|
val supportedTanMethods = tanMethodParameters.map { it.technicalTanMethodIdentification }
|
||||||
val hhd13Supported = supportedTanProcedures.firstOrNull { it.startsWith("hhd1.3", true) } != null
|
val hhd13Supported = supportedTanMethods.firstOrNull { it.startsWith("hhd1.3", true) } != null
|
||||||
val hhd14Supported = supportedTanProcedures.firstOrNull { it.startsWith("hhd1.4", true) } != null
|
val hhd14Supported = supportedTanMethods.firstOrNull { it.startsWith("hhd1.4", true) } != null
|
||||||
|
|
||||||
val supportedHKTANVersions = tanInfo.map { it.segmentVersion }
|
val supportedHKTANVersions = tanInfo.map { it.segmentVersion }
|
||||||
val supportedHKSALVersions = getSupportedVersions(bank, "HKSAL")
|
val supportedHKSALVersions = getSupportedVersions(bank, "HKSAL")
|
||||||
|
@ -184,8 +184,8 @@ class BanksFinTsDetailsRetriever {
|
||||||
|
|
||||||
csvPrinter.printRecord(bankInfo.bankCode, bankInfo.name, bankInfo.city,
|
csvPrinter.printRecord(bankInfo.bankCode, bankInfo.name, bankInfo.city,
|
||||||
bank.bpdVersion,
|
bank.bpdVersion,
|
||||||
bank.tanProceduresSupportedByBank.joinToString(", ") { it.securityFunction.code + ": " + it.displayName + " (" + it.type + ")" },
|
bank.tanMethodSupportedByBank.joinToString(", ") { it.securityFunction.code + ": " + it.displayName + " (" + it.type + ")" },
|
||||||
supportedTanProcedures.joinToString(", "),
|
supportedTanMethods.joinToString(", "),
|
||||||
hhd13Supported,
|
hhd13Supported,
|
||||||
hhd14Supported,
|
hhd14Supported,
|
||||||
supportsHKTAN6,
|
supportsHKTAN6,
|
||||||
|
@ -203,41 +203,41 @@ class BanksFinTsDetailsRetriever {
|
||||||
bank.supportedJobs.joinToString(", ") { it.jobName + " " + it.segmentVersion }
|
bank.supportedJobs.joinToString(", ") { it.jobName + " " + it.segmentVersion }
|
||||||
)
|
)
|
||||||
|
|
||||||
tanProcedureParameters.forEach { procedureParameter ->
|
tanMethodParameters.forEach { methodParameter ->
|
||||||
if (tanProcedureParameter.containsKey(procedureParameter.procedureName) == false) {
|
if (tanMethodParameter.containsKey(methodParameter.methodName) == false) {
|
||||||
tanProcedureParameter.put(procedureParameter.procedureName, mutableSetOf(procedureParameter))
|
tanMethodParameter.put(methodParameter.methodName, mutableSetOf(methodParameter))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tanProcedureParameter[procedureParameter.procedureName]?.add(procedureParameter)
|
tanMethodParameter[methodParameter.methodName]?.add(methodParameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
val tanProcedureType = finTsClient.mapToTanProcedureTypePublic(procedureParameter)
|
val tanMethodType = finTsClient.mapToTanMethodTypePublic(methodParameter)
|
||||||
if (tanProcedureTypes.containsKey(tanProcedureType) == false) {
|
if (tanMethodTypes.containsKey(tanMethodType) == false) {
|
||||||
tanProcedureTypes.put(tanProcedureType, mutableSetOf(procedureParameter))
|
tanMethodTypes.put(tanMethodType, mutableSetOf(methodParameter))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tanProcedureTypes[tanProcedureType]?.add(procedureParameter)
|
tanMethodTypes[tanMethodType]?.add(methodParameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
tanProcedureParameterTechnicalIdentification.add(procedureParameter.technicalTanProcedureIdentification)
|
tanMethodParameterTechnicalIdentification.add(methodParameter.technicalTanMethodIdentification)
|
||||||
tanProcedureParameterVersionZkaTanProcedure.add(procedureParameter.versionZkaTanProcedure)
|
tanMethodParameterVersionZkaTanMethod.add(methodParameter.versionZkaTanMethod)
|
||||||
|
|
||||||
if (procedureParameter.smsDebitAccountRequired == SmsAbbuchungskontoErforderlich.SmsAbbuchungskontoMussAngegebenWerden) {
|
if (methodParameter.smsDebitAccountRequired == SmsAbbuchungskontoErforderlich.SmsAbbuchungskontoMussAngegebenWerden) {
|
||||||
requiresSmsAbbuchungskonto.add(bankInfo)
|
requiresSmsAbbuchungskonto.add(bankInfo)
|
||||||
}
|
}
|
||||||
if (procedureParameter.initiatorAccountRequired == AuftraggeberkontoErforderlich.AuftraggeberkontoMussAngegebenWerdenWennImGeschaeftsvorfallEnthalten) {
|
if (methodParameter.initiatorAccountRequired == AuftraggeberkontoErforderlich.AuftraggeberkontoMussAngegebenWerdenWennImGeschaeftsvorfallEnthalten) {
|
||||||
requiresAuftraggeberkonto.add(bankInfo)
|
requiresAuftraggeberkonto.add(bankInfo)
|
||||||
}
|
}
|
||||||
if (procedureParameter.challengeClassRequired) {
|
if (methodParameter.challengeClassRequired) {
|
||||||
requiresChallengeClass.add(bankInfo)
|
requiresChallengeClass.add(bankInfo)
|
||||||
}
|
}
|
||||||
if (procedureParameter.signatureStructured) {
|
if (methodParameter.signatureStructured) {
|
||||||
signatureStructured.add(bankInfo)
|
signatureStructured.add(bankInfo)
|
||||||
}
|
}
|
||||||
if (procedureParameter.nameOfTanMediaRequired == BezeichnungDesTanMediumsErforderlich.BezeichnungDesTanMediumsMussAngegebenWerden) {
|
if (methodParameter.nameOfTanMediaRequired == BezeichnungDesTanMediumsErforderlich.BezeichnungDesTanMediumsMussAngegebenWerden) {
|
||||||
requiresNameOfTanMedia.add(bankInfo)
|
requiresNameOfTanMedia.add(bankInfo)
|
||||||
}
|
}
|
||||||
if (procedureParameter.hhdUcResponseRequired) {
|
if (methodParameter.hhdUcResponseRequired) {
|
||||||
requiresHhdUcResponse.add(bankInfo)
|
requiresHhdUcResponse.add(bankInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,11 +283,11 @@ class BanksFinTsDetailsRetriever {
|
||||||
private fun printStatistics() {
|
private fun printStatistics() {
|
||||||
log.info("Did not receive response from Banks ${printBanks(requestNotSuccessful)}")
|
log.info("Did not receive response from Banks ${printBanks(requestNotSuccessful)}")
|
||||||
|
|
||||||
log.info("Mapped tanProcedureTypes: ${tanProcedureTypes.map { System.lineSeparator() + it.key + ": " + it.value.map { it.procedureName + " " + it.zkaTanProcedure + " " + it.technicalTanProcedureIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") }}\n\n")
|
log.info("Mapped tanMethodTypes: ${tanMethodTypes.map { System.lineSeparator() + it.key + ": " + it.value.map { it.methodName + " " + it.zkaTanMethod + " " + it.technicalTanMethodIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") }}\n\n")
|
||||||
log.info("TanProcedureParameters:${tanProcedureParameter.map { System.lineSeparator() + it.key + ": " + it.value.map { it.securityFunction.code + " " + it.zkaTanProcedure + " " + it.technicalTanProcedureIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") } }\n\n")
|
log.info("TanMethodParameters:${tanMethodParameter.map { System.lineSeparator() + it.key + ": " + it.value.map { it.securityFunction.code + " " + it.zkaTanMethod + " " + it.technicalTanMethodIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") } }\n\n")
|
||||||
|
|
||||||
log.info("TanProcedureParameters TechnicalIdentification:${tanProcedureParameterTechnicalIdentification.joinToString(", ") } \n\n")
|
log.info("TanMethodParameters TechnicalIdentification:${tanMethodParameterTechnicalIdentification.joinToString(", ") } \n\n")
|
||||||
log.info("TanProcedureParameters VersionZkaTanProcedure:${tanProcedureParameterVersionZkaTanProcedure.joinToString(", ") } \n\n")
|
log.info("TanMethodParameters VersionZkaTanMethod:${tanMethodParameterVersionZkaTanMethod.joinToString(", ") } \n\n")
|
||||||
|
|
||||||
log.info("Requires SmsAbbuchungskonto ${printBanks(requiresSmsAbbuchungskonto)}") // no (only 2)
|
log.info("Requires SmsAbbuchungskonto ${printBanks(requiresSmsAbbuchungskonto)}") // no (only 2)
|
||||||
log.info("Requires Auftraggeberkonto ${printBanks(requiresAuftraggeberkonto)}") // yes, a lot of (12631)
|
log.info("Requires Auftraggeberkonto ${printBanks(requiresAuftraggeberkonto)}") // yes, a lot of (12631)
|
||||||
|
|
|
@ -219,8 +219,8 @@ open class fints4kBankingClient(
|
||||||
protected open fun createFinTsClientCallback(clientCallback: BankingClientCallback): FinTsClientCallback {
|
protected open fun createFinTsClientCallback(clientCallback: BankingClientCallback): FinTsClientCallback {
|
||||||
return object : FinTsClientCallback {
|
return object : FinTsClientCallback {
|
||||||
|
|
||||||
override fun askUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?, callback: (TanProcedure?) -> Unit) {
|
override fun askUserForTanMethod(supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
|
||||||
handleAskUserForTanProcedure(supportedTanProcedures, suggestedTanProcedure, callback)
|
handleAskUserForTanProcedure(supportedTanMethods, suggestedTanMethod, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
|
||||||
|
@ -234,9 +234,9 @@ open class fints4kBankingClient(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleAskUserForTanProcedure(supportedTanProcedures: List<TanProcedure>, suggestedTanProcedure: TanProcedure?, callback: (TanProcedure?) -> Unit) {
|
protected open fun handleAskUserForTanProcedure(supportedTanMethods: List<TanMethod>, suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
|
||||||
// we simply return suggestedTanProcedure as even so it's not user's preferred TAN procedure she still can select it in EnterTanDialog
|
// we simply return suggestedTanProcedure as even so it's not user's preferred TAN procedure she still can select it in EnterTanDialog
|
||||||
callback(suggestedTanProcedure)
|
callback(suggestedTanMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun handleEnterTan(bank: BankData, tanChallenge: TanChallenge, enterTanCallback: (EnterTanResult) -> Unit, clientCallback: BankingClientCallback) {
|
protected open fun handleEnterTan(bank: BankData, tanChallenge: TanChallenge, enterTanCallback: (EnterTanResult) -> Unit, clientCallback: BankingClientCallback) {
|
||||||
|
|
|
@ -81,11 +81,11 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
|
|
||||||
customer.accounts = mapBankAccounts(customer, bank.accounts)
|
customer.accounts = mapBankAccounts(customer, bank.accounts)
|
||||||
|
|
||||||
updateTanMediaAndProcedures(customer, bank)
|
updateTanMediaAndMethods(customer, bank)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In UI only customerId, password, (bankCode,) and selected TAN procedure can be set
|
* In UI only customerId, password, (bankCode,) and selected TAN method can be set
|
||||||
*/
|
*/
|
||||||
open fun mapChangesFromUiToClientModel(customer: TypedCustomer, bank: BankData) {
|
open fun mapChangesFromUiToClientModel(customer: TypedCustomer, bank: BankData) {
|
||||||
bank.customerId = customer.customerId
|
bank.customerId = customer.customerId
|
||||||
|
@ -93,7 +93,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
|
|
||||||
bank.bankCode = customer.bankCode
|
bank.bankCode = customer.bankCode
|
||||||
|
|
||||||
bank.selectedTanProcedure = findTanProcedure(bank, customer.selectedTanProcedure) ?: bank.selectedTanProcedure
|
bank.selectedTanMethod = findTanMethod(bank, customer.selectedTanProcedure) ?: bank.selectedTanMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -235,13 +235,13 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun updateTanMediaAndProcedures(account: TypedCustomer, bank: BankData) {
|
open fun updateTanMediaAndMethods(account: TypedCustomer, bank: BankData) {
|
||||||
account.supportedTanProcedures = bank.tanProceduresAvailableForUser.map { tanProcedure ->
|
account.supportedTanProcedures = bank.tanMethodsAvailableForUser.map { tanMethod ->
|
||||||
findMappedTanProcedure(account, tanProcedure) ?: mapTanProcedure(tanProcedure)
|
findMappedTanMethod(account, tanMethod) ?: mapTanMethod(tanMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bank.isTanProcedureSelected) {
|
if (bank.isTanMethodSelected) {
|
||||||
account.selectedTanProcedure = findMappedTanProcedure(account, bank.selectedTanProcedure)
|
account.selectedTanProcedure = findMappedTanMethod(account, bank.selectedTanMethod)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
account.selectedTanProcedure = null
|
account.selectedTanProcedure = null
|
||||||
|
@ -253,32 +253,32 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun mapTanProcedures(tanProcedures: List<net.dankito.banking.fints.model.TanProcedure>): List<TanProcedure> {
|
open fun mapTanMethods(tanMethods: List<net.dankito.banking.fints.model.TanMethod>): List<TanProcedure> {
|
||||||
return tanProcedures.map { mapTanProcedure(it) }
|
return tanMethods.map { mapTanMethod(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanProcedure(tanProcedure: net.dankito.banking.fints.model.TanProcedure): TanProcedure {
|
open fun mapTanMethod(tanMethod: net.dankito.banking.fints.model.TanMethod): TanProcedure {
|
||||||
return modelCreator.createTanProcedure(
|
return modelCreator.createTanProcedure(
|
||||||
tanProcedure.displayName,
|
tanMethod.displayName,
|
||||||
mapTanProcedureType(tanProcedure.type),
|
mapTanMethodType(tanMethod.type),
|
||||||
tanProcedure.securityFunction.code,
|
tanMethod.securityFunction.code,
|
||||||
tanProcedure.maxTanInputLength,
|
tanMethod.maxTanInputLength,
|
||||||
mapAllowedTanFormat(tanProcedure.allowedTanFormat)
|
mapAllowedTanFormat(tanMethod.allowedTanFormat)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanProcedureType(type: net.dankito.banking.fints.model.TanProcedureType): TanProcedureType {
|
open fun mapTanMethodType(type: net.dankito.banking.fints.model.TanMethodType): TanProcedureType {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
net.dankito.banking.fints.model.TanProcedureType.EnterTan -> TanProcedureType.EnterTan
|
net.dankito.banking.fints.model.TanMethodType.EnterTan -> TanProcedureType.EnterTan
|
||||||
net.dankito.banking.fints.model.TanProcedureType.ChipTanManuell -> TanProcedureType.ChipTanManuell
|
net.dankito.banking.fints.model.TanMethodType.ChipTanManuell -> TanProcedureType.ChipTanManuell
|
||||||
net.dankito.banking.fints.model.TanProcedureType.ChipTanFlickercode -> TanProcedureType.ChipTanFlickercode
|
net.dankito.banking.fints.model.TanMethodType.ChipTanFlickercode -> TanProcedureType.ChipTanFlickercode
|
||||||
net.dankito.banking.fints.model.TanProcedureType.ChipTanUsb -> TanProcedureType.ChipTanUsb
|
net.dankito.banking.fints.model.TanMethodType.ChipTanUsb -> TanProcedureType.ChipTanUsb
|
||||||
net.dankito.banking.fints.model.TanProcedureType.ChipTanQrCode -> TanProcedureType.ChipTanQrCode
|
net.dankito.banking.fints.model.TanMethodType.ChipTanQrCode -> TanProcedureType.ChipTanQrCode
|
||||||
net.dankito.banking.fints.model.TanProcedureType.ChipTanPhotoTanMatrixCode -> TanProcedureType.ChipTanPhotoTanMatrixCode
|
net.dankito.banking.fints.model.TanMethodType.ChipTanPhotoTanMatrixCode -> TanProcedureType.ChipTanPhotoTanMatrixCode
|
||||||
net.dankito.banking.fints.model.TanProcedureType.SmsTan -> TanProcedureType.SmsTan
|
net.dankito.banking.fints.model.TanMethodType.SmsTan -> TanProcedureType.SmsTan
|
||||||
net.dankito.banking.fints.model.TanProcedureType.AppTan -> TanProcedureType.AppTan
|
net.dankito.banking.fints.model.TanMethodType.AppTan -> TanProcedureType.AppTan
|
||||||
net.dankito.banking.fints.model.TanProcedureType.photoTan -> TanProcedureType.photoTan
|
net.dankito.banking.fints.model.TanMethodType.photoTan -> TanProcedureType.photoTan
|
||||||
net.dankito.banking.fints.model.TanProcedureType.QrCode -> TanProcedureType.QrCode
|
net.dankito.banking.fints.model.TanMethodType.QrCode -> TanProcedureType.QrCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,16 +289,16 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findMappedTanProcedure(customer: TypedCustomer, tanProcedure: net.dankito.banking.fints.model.TanProcedure): TanProcedure? {
|
protected open fun findMappedTanMethod(customer: TypedCustomer, tanMethod: net.dankito.banking.fints.model.TanMethod): TanProcedure? {
|
||||||
return customer.supportedTanProcedures.firstOrNull { it.bankInternalProcedureCode == tanProcedure.securityFunction.code }
|
return customer.supportedTanProcedures.firstOrNull { it.bankInternalProcedureCode == tanMethod.securityFunction.code }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findTanProcedure(bank: BankData, tanProcedure: TanProcedure?): net.dankito.banking.fints.model.TanProcedure? {
|
protected open fun findTanMethod(bank: BankData, tanProcedure: TanProcedure?): net.dankito.banking.fints.model.TanMethod? {
|
||||||
if (tanProcedure == null) {
|
if (tanProcedure == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return bank.tanProceduresAvailableForUser.firstOrNull { it.securityFunction.code == tanProcedure.bankInternalProcedureCode }
|
return bank.tanMethodsAvailableForUser.firstOrNull { it.securityFunction.code == tanProcedure.bankInternalProcedureCode }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findMappedTanMedium(customer: TypedCustomer, tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium? {
|
protected open fun findMappedTanMedium(customer: TypedCustomer, tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium? {
|
||||||
|
@ -393,29 +393,29 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun mapTanProcedure(tanProcedure: TanProcedure): net.dankito.banking.fints.model.TanProcedure {
|
open fun mapTanMethod(tanProcedure: TanProcedure): net.dankito.banking.fints.model.TanMethod {
|
||||||
return net.dankito.banking.fints.model.TanProcedure(
|
return net.dankito.banking.fints.model.TanMethod(
|
||||||
tanProcedure.displayName,
|
tanProcedure.displayName,
|
||||||
Sicherheitsfunktion.values().first { it.code == tanProcedure.bankInternalProcedureCode },
|
Sicherheitsfunktion.values().first { it.code == tanProcedure.bankInternalProcedureCode },
|
||||||
mapTanProcedureType(tanProcedure.type),
|
mapTanMethodType(tanProcedure.type),
|
||||||
null, // TODO: where to get HDD Version from?
|
null, // TODO: where to get HDD Version from?
|
||||||
tanProcedure.maxTanInputLength,
|
tanProcedure.maxTanInputLength,
|
||||||
mapAllowedTanFormat(tanProcedure.allowedTanFormat)
|
mapAllowedTanFormat(tanProcedure.allowedTanFormat)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanProcedureType(type: TanProcedureType): net.dankito.banking.fints.model.TanProcedureType {
|
open fun mapTanMethodType(type: TanProcedureType): net.dankito.banking.fints.model.TanMethodType {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
TanProcedureType.EnterTan -> net.dankito.banking.fints.model.TanProcedureType.EnterTan
|
TanProcedureType.EnterTan -> net.dankito.banking.fints.model.TanMethodType.EnterTan
|
||||||
TanProcedureType.ChipTanManuell -> net.dankito.banking.fints.model.TanProcedureType.ChipTanManuell
|
TanProcedureType.ChipTanManuell -> net.dankito.banking.fints.model.TanMethodType.ChipTanManuell
|
||||||
TanProcedureType.ChipTanFlickercode -> net.dankito.banking.fints.model.TanProcedureType.ChipTanFlickercode
|
TanProcedureType.ChipTanFlickercode -> net.dankito.banking.fints.model.TanMethodType.ChipTanFlickercode
|
||||||
TanProcedureType.ChipTanUsb -> net.dankito.banking.fints.model.TanProcedureType.ChipTanUsb
|
TanProcedureType.ChipTanUsb -> net.dankito.banking.fints.model.TanMethodType.ChipTanUsb
|
||||||
TanProcedureType.ChipTanQrCode -> net.dankito.banking.fints.model.TanProcedureType.ChipTanQrCode
|
TanProcedureType.ChipTanQrCode -> net.dankito.banking.fints.model.TanMethodType.ChipTanQrCode
|
||||||
TanProcedureType.ChipTanPhotoTanMatrixCode -> net.dankito.banking.fints.model.TanProcedureType.ChipTanPhotoTanMatrixCode
|
TanProcedureType.ChipTanPhotoTanMatrixCode -> net.dankito.banking.fints.model.TanMethodType.ChipTanPhotoTanMatrixCode
|
||||||
TanProcedureType.SmsTan -> net.dankito.banking.fints.model.TanProcedureType.SmsTan
|
TanProcedureType.SmsTan -> net.dankito.banking.fints.model.TanMethodType.SmsTan
|
||||||
TanProcedureType.AppTan -> net.dankito.banking.fints.model.TanProcedureType.AppTan
|
TanProcedureType.AppTan -> net.dankito.banking.fints.model.TanMethodType.AppTan
|
||||||
TanProcedureType.photoTan -> net.dankito.banking.fints.model.TanProcedureType.photoTan
|
TanProcedureType.photoTan -> net.dankito.banking.fints.model.TanMethodType.photoTan
|
||||||
TanProcedureType.QrCode -> net.dankito.banking.fints.model.TanProcedureType.QrCode
|
TanProcedureType.QrCode -> net.dankito.banking.fints.model.TanMethodType.QrCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,8 +427,8 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapEnterTanResult(result: EnterTanResult, bank: BankData): net.dankito.banking.fints.model.EnterTanResult {
|
open fun mapEnterTanResult(result: EnterTanResult, bank: BankData): net.dankito.banking.fints.model.EnterTanResult {
|
||||||
result.changeTanProcedureTo?.let { changeTanProcedureTo ->
|
result.changeTanProcedureTo?.let { changeTanMethodTo ->
|
||||||
return net.dankito.banking.fints.model.EnterTanResult.userAsksToChangeTanProcedure(mapTanProcedure(changeTanProcedureTo))
|
return net.dankito.banking.fints.model.EnterTanResult.userAsksToChangeTanMethod(mapTanMethod(changeTanMethodTo))
|
||||||
}
|
}
|
||||||
|
|
||||||
result.changeTanMediumTo?.let { changeTanMediumTo ->
|
result.changeTanMediumTo?.let { changeTanMediumTo ->
|
||||||
|
@ -462,13 +462,13 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return TanChallenge(tanChallenge.messageToShowToUser,
|
return TanChallenge(tanChallenge.messageToShowToUser,
|
||||||
mapTanProcedure(tanChallenge.tanProcedure)
|
mapTanMethod(tanChallenge.tanMethod)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun mapTanChallenge(tanChallenge: net.dankito.banking.fints.model.FlickerCodeTanChallenge): FlickerCodeTanChallenge {
|
open fun mapTanChallenge(tanChallenge: net.dankito.banking.fints.model.FlickerCodeTanChallenge): FlickerCodeTanChallenge {
|
||||||
return FlickerCodeTanChallenge(mapFlickerCode(tanChallenge.flickerCode), tanChallenge.messageToShowToUser,
|
return FlickerCodeTanChallenge(mapFlickerCode(tanChallenge.flickerCode), tanChallenge.messageToShowToUser,
|
||||||
mapTanProcedure(tanChallenge.tanProcedure)
|
mapTanMethod(tanChallenge.tanMethod)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) {
|
||||||
|
|
||||||
open fun mapTanChallenge(tanChallenge: net.dankito.banking.fints.model.ImageTanChallenge): ImageTanChallenge {
|
open fun mapTanChallenge(tanChallenge: net.dankito.banking.fints.model.ImageTanChallenge): ImageTanChallenge {
|
||||||
return ImageTanChallenge(mapTanImage(tanChallenge.image), tanChallenge.messageToShowToUser,
|
return ImageTanChallenge(mapTanImage(tanChallenge.image), tanChallenge.messageToShowToUser,
|
||||||
mapTanProcedure(tanChallenge.tanProcedure)
|
mapTanMethod(tanChallenge.tanMethod)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue