Added option to control if sensitive data should get removed from messageLog

This commit is contained in:
dankito 2024-08-20 13:32:42 +02:00
parent 0361a0e6b8
commit 9a7615fe88
8 changed files with 27 additions and 20 deletions

View File

@ -53,7 +53,7 @@ open class FinTsClient(
if (getAccountInfoResponse.successful == false || param.retrieveOnlyAccountInfo) {
return GetAccountDataResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse), null,
getAccountInfoResponse.messageLogWithoutSensitiveData, bank)
getAccountInfoResponse.messageLog, bank)
} else {
return getAccountData(param, getAccountInfoResponse.bank, getAccountInfoResponse.bank.accounts, getAccountInfoResponse)
}
@ -69,7 +69,7 @@ open class FinTsClient(
if (accountsSupportingRetrievingTransactions.isEmpty()) {
val errorMessage = "None of the accounts ${accounts.map { it.productName }} supports retrieving balance or transactions" // TODO: translate
return GetAccountDataResponse(ErrorCode.NoneOfTheAccountsSupportsRetrievingData, errorMessage, mapper.map(bank), previousJobResponse?.messageLogWithoutSensitiveData ?: listOf(), bank)
return GetAccountDataResponse(ErrorCode.NoneOfTheAccountsSupportsRetrievingData, errorMessage, mapper.map(bank), previousJobResponse?.messageLog ?: listOf(), bank)
}
accountsSupportingRetrievingTransactions.forEach { account ->
@ -115,7 +115,7 @@ open class FinTsClient(
if (getAccountInfoResponse.successful == false) {
return TransferMoneyResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse),
getAccountInfoResponse.messageLogWithoutSensitiveData, bank)
getAccountInfoResponse.messageLog, bank)
} else {
return transferMoneyAsync(param, recipientBankIdentifier, getAccountInfoResponse.bank, getAccountInfoResponse.bank.accounts, getAccountInfoResponse)
}
@ -129,14 +129,14 @@ open class FinTsClient(
val accountToUse: AccountData
if (accountsSupportingTransfer.isEmpty()) {
return TransferMoneyResponse(ErrorCode.NoAccountSupportsMoneyTransfer, "None of the accounts $accounts supports money transfer", previousJobResponse?.messageLogWithoutSensitiveData ?: listOf(), bank)
return TransferMoneyResponse(ErrorCode.NoAccountSupportsMoneyTransfer, "None of the accounts $accounts supports money transfer", previousJobResponse?.messageLog ?: listOf(), bank)
} else if (accountsSupportingTransfer.size == 1) {
accountToUse = accountsSupportingTransfer.first()
} else {
val selectedAccount = param.selectAccountToUseForTransfer?.invoke(accountsSupportingTransfer)
if (selectedAccount == null) {
return TransferMoneyResponse(ErrorCode.MoreThanOneAccountSupportsMoneyTransfer, "More than one of the accounts $accountsSupportingTransfer supports money transfer, so we cannot clearly determine which one to use for this transfer", previousJobResponse?.messageLogWithoutSensitiveData ?: listOf(), bank)
return TransferMoneyResponse(ErrorCode.MoreThanOneAccountSupportsMoneyTransfer, "More than one of the accounts $accountsSupportingTransfer supports money transfer, so we cannot clearly determine which one to use for this transfer", previousJobResponse?.messageLog ?: listOf(), bank)
}
accountToUse = selectedAccount

View File

@ -20,7 +20,7 @@ open class FinTsClientForCustomer(
protected val client = FinTsClientDeprecated(config, callback)
open val messageLogWithoutSensitiveData: List<MessageLogEntry> = mutableListOf()
open val messageLog: List<MessageLogEntry> = mutableListOf()
open suspend fun addAccountAsync(): AddAccountResponse {

View File

@ -3,6 +3,7 @@ package net.dankito.banking.fints.config
import net.dankito.banking.fints.model.ProductData
data class FinTsClientOptions(
val removeSensitiveDataFromMessageLog: Boolean = true,
val version: String = "1.0.0", // TODO: get version dynamically
val productName: String = "15E53C26816138699C7B6A3E8"
) {

View File

@ -1,8 +1,8 @@
package net.dankito.banking.fints.log
import net.codinux.log.Logger
import net.codinux.log.LoggerFactory
import net.codinux.log.logger
import net.dankito.banking.fints.config.FinTsClientOptions
import net.dankito.banking.fints.model.BankData
import net.dankito.banking.fints.model.MessageLogEntry
import net.dankito.banking.fints.model.MessageLogEntryType
@ -12,7 +12,9 @@ import net.dankito.banking.fints.extensions.toStringWithMinDigits
import kotlin.reflect.KClass
open class MessageLogCollector {
open class MessageLogCollector(
private val options: FinTsClientOptions = FinTsClientOptions()
) {
companion object {
val FindAccountTransactionsStartRegex = Regex("^HIKAZ:\\d:\\d:\\d\\+@\\d+@", RegexOption.MULTILINE)
@ -26,12 +28,12 @@ open class MessageLogCollector {
}
protected open val messageLog = ArrayList<MessageLogEntry>() // TODO: make thread safe like with CopyOnWriteArrayList
protected open val _messageLog = ArrayList<MessageLogEntry>() // TODO: make thread safe like with CopyOnWriteArrayList
// in either case remove sensitive data after response is parsed as otherwise some information like account holder name and accounts may is not set yet on BankData
open val messageLogWithoutSensitiveData: List<MessageLogEntry>
open val messageLog: List<MessageLogEntry>
// safe CPU cycles by only formatting and removing sensitive data if messageLog is really requested
get() = messageLog.map { MessageLogEntry(it.type, it.context, it.messageTrace, createMessageForLog(it), it.error, it.time) }
get() = _messageLog.map { MessageLogEntry(it.type, it.context, it.messageTrace, createMessageForLog(it), it.error, it.time) }
private fun createMessageForLog(logEntry: MessageLogEntry): String {
val message = if (logEntry.type == MessageLogEntryType.Error) {
@ -40,7 +42,11 @@ open class MessageLogCollector {
logEntry.messageTrace + "\n" + prettyPrintHbciMessage(logEntry.message)
}
return safelyRemoveSensitiveDataFromMessage(message, logEntry.context.bank)
return if (options.removeSensitiveDataFromMessageLog) {
safelyRemoveSensitiveDataFromMessage(message, logEntry.context.bank)
} else {
message
}
}
@ -62,7 +68,7 @@ open class MessageLogCollector {
}
protected open fun addMessageLogEntry(type: MessageLogEntryType, context: MessageContext, messageTrace: String, message: String, error: Throwable? = null) {
messageLog.add(MessageLogEntry(type, context, messageTrace, message, error))
_messageLog.add(MessageLogEntry(type, context, messageTrace, message, error))
}

View File

@ -158,7 +158,7 @@ open class FinTsModelMapper {
}
open fun mergeMessageLog(vararg responses: FinTsClientResponse?): List<MessageLogEntry> {
return responses.filterNotNull().flatMap { it.messageLogWithoutSensitiveData }
return responses.filterNotNull().flatMap { it.messageLog }
}
}

View File

@ -24,7 +24,7 @@ open class JobContext(
* Only set if the current context is for a specific account (like get account's transactions).
*/
open val account: AccountData? = null,
protected open val messageLogCollector: MessageLogCollector = MessageLogCollector()
protected open val messageLogCollector: MessageLogCollector = MessageLogCollector(config.options)
) : MessageBaseData(bank, config.options.product), IMessageLogAppender {
companion object {
@ -38,8 +38,8 @@ open class JobContext(
open val responseParser: ResponseParser = ResponseParser(logAppender = this)
open val messageLogWithoutSensitiveData: List<MessageLogEntry>
get() = messageLogCollector.messageLogWithoutSensitiveData
open val messageLog: List<MessageLogEntry>
get() = messageLogCollector.messageLog
open var dialog: DialogContext = DialogContext() // create null value so that variable is not null

View File

@ -17,7 +17,7 @@ open class FinTsClientResponse(
open val isStrongAuthenticationRequired: Boolean,
open val tanRequired: TanResponse? = null,
open val messageLogWithoutSensitiveData: List<MessageLogEntry>,
open val messageLog: List<MessageLogEntry>,
/**
* A fints4k internal error like an error occurred during web request or response parsing.
@ -43,7 +43,7 @@ open class FinTsClientResponse(
constructor(context: JobContext, response: BankResponse) : this(response.successful, response.didReceiveResponse, response.noTanMethodSelected,
response.isStrongAuthenticationRequired, response.tanResponse, context.messageLogWithoutSensitiveData,
response.isStrongAuthenticationRequired, response.tanResponse, context.messageLog,
response.internalError, response.errorsToShowToUser, response.isPinLocked, response.wrongCredentialsEntered,
response.tanRequiredButUserDidNotEnterOne, response.tanRequiredButWeWereToldToAbortIfSo,
response.messageThatCouldNotBeCreated?.isJobAllowed ?: true,

View File

@ -8,7 +8,7 @@ open class GetTransactionsResponse(
errorMessage: String? = null
) : FinTsClientResponse(isSuccessful(retrievedResponses), retrievedResponses.all { it.didReceiveResponse }, retrievedResponses.any { it.noTanMethodSelected },
retrievedResponses.any { it.isStrongAuthenticationRequired }, retrievedResponses.map { it.tanRequired }.firstOrNull(),
retrievedResponses.flatMap { it.messageLogWithoutSensitiveData },
retrievedResponses.flatMap { it.messageLog },
errorMessage ?: retrievedResponses.mapNotNull { it.internalError }.joinToString("\r\n"),
retrievedResponses.flatMap { it.errorMessagesFromBank }, retrievedResponses.any { it.isPinLocked },
retrievedResponses.any { it.wrongCredentialsEntered }, retrievedResponses.any { it.userCancelledAction },