Added preferredTanMethods and preferredTanMedium to JobContext

This commit is contained in:
dankito 2024-09-10 02:37:02 +02:00
parent 6bf7fdcb44
commit 61d8f2c342
4 changed files with 31 additions and 25 deletions

View File

@ -80,7 +80,7 @@ open class FinTsClient(
} }
protected open suspend fun getAccountTransactions(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse { protected open suspend fun getAccountTransactions(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse {
val context = JobContext(JobContextType.GetTransactions, this.callback, config, bank, account) val context = JobContext(JobContextType.GetTransactions, this.callback, config, bank, account, param.preferredTanMethods, param.preferredTanMedium)
return config.jobExecutor.getTransactionsAsync(context, mapper.toGetAccountTransactionsParameter(param, bank, account)) return config.jobExecutor.getTransactionsAsync(context, mapper.toGetAccountTransactionsParameter(param, bank, account))
} }
@ -138,7 +138,7 @@ open class FinTsClient(
accountToUse = selectedAccount accountToUse = selectedAccount
} }
val context = JobContext(JobContextType.TransferMoney, this.callback, config, bank, accountToUse) val context = JobContext(JobContextType.TransferMoney, this.callback, config, bank, accountToUse, param.preferredTanMethods, param.preferredTanMedium)
val response = config.jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier, val response = config.jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier,
param.amount, param.reference, param.instantPayment)) param.amount, param.reference, param.instantPayment))
@ -205,11 +205,11 @@ open class FinTsClient(
// return GetAccountInfoResponse(it) // return GetAccountInfoResponse(it)
} }
val context = JobContext(JobContextType.GetAccountInfo, this.callback, config, bank) val context = JobContext(JobContextType.GetAccountInfo, this.callback, config, bank, null, param.preferredTanMethods, param.preferredTanMedium)
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */ /* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, param.preferredTanMethods, param.preferredTanMedium) val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context)
/* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with /* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with
strong customer authorization TAN media is required */ strong customer authorization TAN media is required */

View File

@ -1,7 +1,5 @@
package net.codinux.banking.fints package net.codinux.banking.fints
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.datetime.* import kotlinx.datetime.*
import net.codinux.banking.fints.callback.FinTsClientCallback import net.codinux.banking.fints.callback.FinTsClientCallback
import net.codinux.banking.fints.config.FinTsClientConfiguration import net.codinux.banking.fints.config.FinTsClientConfiguration
@ -39,13 +37,13 @@ open class FinTsClientDeprecated(
} }
open suspend fun addAccountAsync(parameter: AddAccountParameter): AddAccountResponse { open suspend fun addAccountAsync(param: AddAccountParameter): AddAccountResponse {
val bank = parameter.bank val bank = param.bank
val context = JobContext(JobContextType.AddAccount, this.callback, config, bank) val context = JobContext(JobContextType.AddAccount, this.callback, config, bank, null, param.preferredTanMethods, param.preferredTanMedium)
/* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */ /* First dialog: Get user's basic data like BPD, customer system ID and her TAN methods */
val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context, parameter.preferredTanMethods, parameter.preferredTanMedium) val newUserInfoResponse = config.jobExecutor.retrieveBasicDataLikeUsersTanMethods(context)
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
return AddAccountResponse(context, newUserInfoResponse) return AddAccountResponse(context, newUserInfoResponse)
@ -54,7 +52,7 @@ open class FinTsClientDeprecated(
/* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with /* Second dialog, executed in retrieveBasicDataLikeUsersTanMethods() if required: some banks require that in order to initialize a dialog with
strong customer authorization TAN media is required */ strong customer authorization TAN media is required */
return addAccountGetAccountsAndTransactions(context, parameter) return addAccountGetAccountsAndTransactions(context, param)
} }
protected open suspend fun addAccountGetAccountsAndTransactions(context: JobContext, parameter: AddAccountParameter): AddAccountResponse { protected open suspend fun addAccountGetAccountsAndTransactions(context: JobContext, parameter: AddAccountParameter): AddAccountResponse {
@ -120,11 +118,11 @@ open class FinTsClientDeprecated(
return GetAccountTransactionsParameter(bank, account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true) return GetAccountTransactionsParameter(bank, account, account.supportsRetrievingBalance, ninetyDaysAgo, abortIfTanIsRequired = true)
} }
open suspend fun getAccountTransactionsAsync(parameter: GetAccountTransactionsParameter): GetAccountTransactionsResponse { open suspend fun getAccountTransactionsAsync(param: GetAccountTransactionsParameter): GetAccountTransactionsResponse {
val context = JobContext(JobContextType.GetTransactions, this.callback, config, parameter.bank, parameter.account) val context = JobContext(JobContextType.GetTransactions, this.callback, config, param.bank, param.account)
return config.jobExecutor.getTransactionsAsync(context, parameter) return config.jobExecutor.getTransactionsAsync(context, param)
} }

View File

@ -20,6 +20,7 @@ import net.codinux.banking.fints.response.segments.*
import net.codinux.banking.fints.tan.FlickerCodeDecoder import net.codinux.banking.fints.tan.FlickerCodeDecoder
import net.codinux.banking.fints.tan.TanImageDecoder import net.codinux.banking.fints.tan.TanImageDecoder
import net.codinux.banking.fints.util.TanMethodSelector import net.codinux.banking.fints.util.TanMethodSelector
import net.codinux.log.Log
import kotlin.math.max import kotlin.math.max
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@ -73,8 +74,7 @@ open class FinTsJobExecutor(
* *
* Be aware this method resets BPD, UPD and selected TAN method! * Be aware this method resets BPD, UPD and selected TAN method!
*/ */
open suspend fun retrieveBasicDataLikeUsersTanMethods(context: JobContext, preferredTanMethods: List<TanMethodType>? = null, preferredTanMedium: String? = null, open suspend fun retrieveBasicDataLikeUsersTanMethods(context: JobContext): BankResponse {
closeDialog: Boolean = false): BankResponse {
val bank = context.bank val bank = context.bank
// 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),
@ -90,7 +90,7 @@ open class FinTsJobExecutor(
bank.resetSelectedTanMethod() bank.resetSelectedTanMethod()
// this is the only case where Einschritt-TAN-Verfahren is accepted: to get user's TAN methods // this is the only case where Einschritt-TAN-Verfahren is accepted: to get user's TAN methods
context.startNewDialog(closeDialog, versionOfSecurityProcedure = VersionDesSicherheitsverfahrens.Version_1) context.startNewDialog(versionOfSecurityProcedure = VersionDesSicherheitsverfahrens.Version_1)
val message = messageBuilder.createInitDialogMessage(context) val message = messageBuilder.createInitDialogMessage(context)
@ -103,12 +103,10 @@ open class FinTsJobExecutor(
if (bank.tanMethodsAvailableForUser.isEmpty()) { // could not retrieve supported tan methods for user if (bank.tanMethodsAvailableForUser.isEmpty()) { // could not retrieve supported tan methods for user
return getTanMethodsResponse return getTanMethodsResponse
} else { } else {
getUsersTanMethod(context, preferredTanMethods) getUsersTanMethod(context)
if (bank.isTanMethodSelected == false) { if (bank.isTanMethodSelected && bank.tanMedia.isEmpty() && bank.tanMethodsAvailableForUser.any { it.nameOfTanMediumRequired } && isJobSupported(bank, CustomerSegmentId.TanMediaList)) { // tan media not retrieved yet
return getTanMethodsResponse getTanMediaList(context, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien, context.preferredTanMedium)
} else if (bank.tanMedia.isEmpty() && isJobSupported(bank, CustomerSegmentId.TanMediaList)) { // tan media not retrieved yet
getTanMediaList(context, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien, preferredTanMedium)
return getTanMethodsResponse // TODO: judge if bank requires selecting TAN media and if though evaluate getTanMediaListResponse return getTanMethodsResponse // TODO: judge if bank requires selecting TAN media and if though evaluate getTanMediaListResponse
} else { } else {
@ -384,14 +382,22 @@ open class FinTsJobExecutor(
mayRetrieveAutomaticallyIfUserEnteredDecoupledTan(context, tanChallenge, tanResponse) mayRetrieveAutomaticallyIfUserEnteredDecoupledTan(context, tanChallenge, tanResponse)
var invocationCount = 0 // TODO: remove again
while (tanChallenge.isEnteringTanDone == false) { while (tanChallenge.isEnteringTanDone == false) {
delay(500) delay(500)
if (++invocationCount % 10 == 0) {
Log.info { "Waiting for TAN input invocation count: $invocationCount" }
}
val now = Instant.nowExt() val now = Instant.nowExt()
if ((tanChallenge.tanExpirationTime != null && now > tanChallenge.tanExpirationTime) || if ((tanChallenge.tanExpirationTime != null && now > tanChallenge.tanExpirationTime) ||
// most TANs a valid 5 - 15 minutes. So terminate wait process after that time // most TANs a valid 5 - 15 minutes. So terminate wait process after that time
(tanChallenge.tanExpirationTime == null && now > tanChallenge.challengeCreationTimestamp.plusMinutes(15))) { (tanChallenge.tanExpirationTime == null && now > tanChallenge.challengeCreationTimestamp.plusMinutes(15))) {
if (tanChallenge.isEnteringTanDone == false) { if (tanChallenge.isEnteringTanDone == false) {
Log.info { "Terminating waiting for TAN input" } // TODO: remove again
tanChallenge.tanExpired() tanChallenge.tanExpired()
} }
@ -624,7 +630,7 @@ open class FinTsJobExecutor(
protected open suspend fun initDialogWithStrongCustomerAuthenticationAfterSuccessfulPreconditionChecks(context: JobContext): BankResponse { protected open suspend fun initDialogWithStrongCustomerAuthenticationAfterSuccessfulPreconditionChecks(context: JobContext): BankResponse {
context.startNewDialog(false) // don't know if it's ok for all invocations of this method to set closeDialog to false (was actually only set in getAccounts()) context.startNewDialog() // don't know if it's ok for all invocations of this method to set closeDialog to false (was actually only set in getAccounts())
val message = messageBuilder.createInitDialogMessage(context) val message = messageBuilder.createInitDialogMessage(context)
@ -700,7 +706,7 @@ open class FinTsJobExecutor(
return BankResponse(true, noTanMethodSelected = noTanMethodSelected, internalError = errorMessage) return BankResponse(true, noTanMethodSelected = noTanMethodSelected, internalError = errorMessage)
} }
open suspend fun getUsersTanMethod(context: JobContext, preferredTanMethods: List<TanMethodType>? = null): Boolean { open suspend fun getUsersTanMethod(context: JobContext): Boolean {
val bank = context.bank val bank = context.bank
if (bank.tanMethodsAvailableForUser.size == 1) { // user has only one TAN method -> set it and we're done if (bank.tanMethodsAvailableForUser.size == 1) { // user has only one TAN method -> set it and we're done
@ -708,7 +714,7 @@ open class FinTsJobExecutor(
return true return true
} }
else { else {
tanMethodSelector.findPreferredTanMethod(bank.tanMethodsAvailableForUser, preferredTanMethods)?.let { tanMethodSelector.findPreferredTanMethod(bank.tanMethodsAvailableForUser, context.preferredTanMethods)?.let {
bank.selectedTanMethod = it bank.selectedTanMethod = it
return true return true
} }

View File

@ -25,6 +25,8 @@ open class JobContext(
* Only set if the current context is for a specific account (like get account's transactions). * Only set if the current context is for a specific account (like get account's transactions).
*/ */
open val account: AccountData? = null, open val account: AccountData? = null,
open val preferredTanMethods: List<TanMethodType>? = null,
open val preferredTanMedium: String? = null,
protected open val messageLogCollector: MessageLogCollector = MessageLogCollector(callback, config.options) protected open val messageLogCollector: MessageLogCollector = MessageLogCollector(callback, config.options)
) : MessageBaseData(bank, config.options.product), IMessageLogAppender { ) : MessageBaseData(bank, config.options.product), IMessageLogAppender {