From e583ba1408ab97333c7873ab3b6d4bad92d43fcd Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 16 Sep 2026 07:13:32 +0200 Subject: [PATCH] Do not log IBANs and account numbers in FinTS (#182342) --- homeassistant/components/fints/sensor.py | 16 ++-- tests/components/fints/test_sensor.py | 110 +++++++++++++++++++++++ 2 files changed, 115 insertions(+), 11 deletions(-) create mode 100644 tests/components/fints/test_sensor.py diff --git a/homeassistant/components/fints/sensor.py b/homeassistant/components/fints/sensor.py index c1afe9e3b7f4..7a1ec4a347e8 100644 --- a/homeassistant/components/fints/sensor.py +++ b/homeassistant/components/fints/sensor.py @@ -87,28 +87,24 @@ def setup_platform( for account in balance_accounts: if config[CONF_ACCOUNTS] and account.iban not in account_config: - _LOGGER.debug("Skipping account %s for bank %s", account.iban, fints_name) + _LOGGER.debug("Skipping account for bank %s", fints_name) continue if not (account_name := account_config.get(account.iban)): account_name = f"{fints_name} - {account.iban}" accounts.append(FinTsAccount(client, account, account_name)) - _LOGGER.debug("Creating account %s for bank %s", account.iban, fints_name) + _LOGGER.debug("Creating account for bank %s", fints_name) for account in holdings_accounts: if config[CONF_HOLDINGS] and account.accountnumber not in holdings_config: - _LOGGER.debug( - "Skipping holdings %s for bank %s", account.accountnumber, fints_name - ) + _LOGGER.debug("Skipping holdings for bank %s", fints_name) continue account_name = holdings_config.get(account.accountnumber) if not account_name: account_name = f"{fints_name} - {account.accountnumber}" accounts.append(FinTsHoldingsAccount(client, account, account_name)) - _LOGGER.debug( - "Creating holdings %s for bank %s", account.accountnumber, fints_name - ) + _LOGGER.debug("Creating holdings for bank %s", fints_name) add_entities(accounts, True) @@ -216,9 +212,7 @@ class FinTsClient: else: _LOGGER.warning( - "Could not determine type of account %s from %s", - account.iban, - self.client.user_id, + "Could not determine type of account for bank %s", self.name ) return balance_accounts, holdings_accounts diff --git a/tests/components/fints/test_sensor.py b/tests/components/fints/test_sensor.py new file mode 100644 index 000000000000..26cbce6aef01 --- /dev/null +++ b/tests/components/fints/test_sensor.py @@ -0,0 +1,110 @@ +"""Tests for the FinTS sensor platform.""" + +import logging +from unittest.mock import MagicMock, patch + +from fints.client import BankIdentifier, FinTSOperations +import pytest + +from homeassistant.components.fints.sensor import SEPAAccount +from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component + +BANK_INFORMATION = { + "bank_identifier": BankIdentifier(country_identifier="280", bank_code="50010517"), + "currency": "EUR", + "customer_id": "0815", + "owner_name": ["SURNAME, FIRSTNAME"], + "subaccount_number": None, + "supported_operations": { + FinTSOperations.GET_BALANCE: True, + FinTSOperations.GET_HOLDINGS: True, + FinTSOperations.GET_SEPA_ACCOUNTS: True, + }, +} + +# GIRO2 and DEPOT2 are deliberately left out of the configuration below, so the +# platform skips them. UNKNOWN has no type and matches neither config. +ACCOUNT_TYPES = {"GIRO1": 5, "GIRO2": 5, "DEPOT1": 33, "DEPOT2": 33, "UNKNOWN": None} + +CONFIG = { + "sensor": { + "platform": "fints", + "bank_identification_number": "12345678", + "username": "user", + "pin": "1234", + "url": "https://example.com", + "name": "Test Bank", + "accounts": [{"account": "GIRO1", "name": "Checking"}], + "holdings": [{"account": "DEPOT1", "name": "Depot"}], + } +} + + +def _sepa_account(identifier: str) -> SEPAAccount: + """Build a SEPA account with the same IBAN and account number.""" + return SEPAAccount( + iban=identifier, + bic="BANCODELTEST", + accountnumber=identifier, + subaccount=None, + blz="12345", + ) + + +@pytest.fixture +def mock_bank() -> MagicMock: + """Return a bank that serves one of every account we care about.""" + bank = MagicMock() + bank.get_sepa_accounts.return_value = [ + _sepa_account(identifier) for identifier in ACCOUNT_TYPES + ] + bank.get_information.return_value = { + "accounts": [ + BANK_INFORMATION + | {"account_number": identifier, "iban": identifier, "type": account_type} + for identifier, account_type in ACCOUNT_TYPES.items() + ] + } + bank.get_balance.return_value.amount.amount = 1234.56 + bank.get_balance.return_value.amount.currency = "EUR" + bank.get_holdings.return_value = [] + return bank + + +async def test_setup_platform( + hass: HomeAssistant, mock_bank: MagicMock, caplog: pytest.LogCaptureFixture +) -> None: + """Only configured accounts get a sensor, and the rest are skipped.""" + caplog.set_level(logging.DEBUG) + + with patch( + "homeassistant.components.fints.sensor.FinTS3PinTanClient", + return_value=mock_bank, + ): + assert await async_setup_component(hass, "sensor", CONFIG) + await hass.async_block_till_done() + + assert hass.states.get("sensor.checking").state == "1234.56" + assert hass.states.get("sensor.depot").state == "0" + + assert "Skipping account for bank Test Bank" in caplog.text + assert "Skipping holdings for bank Test Bank" in caplog.text + assert "Could not determine type of account for bank Test Bank" in caplog.text + + +async def test_account_identifiers_are_not_logged( + hass: HomeAssistant, mock_bank: MagicMock, caplog: pytest.LogCaptureFixture +) -> None: + """No IBAN or account number ends up in the log.""" + caplog.set_level(logging.DEBUG) + + with patch( + "homeassistant.components.fints.sensor.FinTS3PinTanClient", + return_value=mock_bank, + ): + assert await async_setup_component(hass, "sensor", CONFIG) + await hass.async_block_till_done() + + for identifier in ACCOUNT_TYPES: + assert identifier not in caplog.text