ebicsclient 1.3.1__tar.gz → 1.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/PKG-INFO +12 -1
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/README.md +11 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/06-engineering-conventions.md +8 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/pyproject.toml +1 -1
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/models.py +1 -1
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_input_validation.py +4 -4
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/uv.lock +1 -1
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/.github/workflows/ci.yml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/.github/workflows/release.yml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/.gitignore +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/CLAUDE.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/CONTRIBUTING.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/LICENSE.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/01-protocol-and-formats.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/02-licensing-strategy.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/03-library-landscape.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/04-implementation-plan.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/05-zkb-onboarding.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/07-handshake-testing.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/08-parity-and-xsd-findings.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/09-zkb-test-platform-settings.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/10-btf-order-types.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/docs/11-certificate-profiles.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/examples/zkb_handshake.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/__init__.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/certificates.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/client.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/crypto.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/errors.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/__init__.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/camt.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/camt052.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/camt053.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/camt054.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/container.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/formats/pain002.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/keys.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/letter.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/protocol/__init__.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/protocol/h005.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/py.typed +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/src/ebicsclient/transport.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/crypto_helpers.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/camt052_zkb_sample.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/camt053_zkb_sample.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/camt054_collective_zkb_sample.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/camt054_credit_zkb_sample.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/camt054_debit_zkb_sample.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/htd_zkb_sample.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/pain002_accp.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/pain002_actc.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/pain002_part.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/data/pain002_rjct.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/fixtures/parity/hia.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/fixtures/parity/hpb.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/fixtures/parity/ini.xml +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/fixtures/parity/meta.json +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_c14n_vectors.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_camt052_054.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_camt053.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_certificates.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_client.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_crypto.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_errors.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_h005.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_keys.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_letter.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_pain002.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_php_parity.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_schema_validation.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tests/test_transport.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tools/fetch-schemas.py +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tools/php-parity/README.md +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tools/php-parity/composer.json +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tools/php-parity/composer.lock +0 -0
- {ebicsclient-1.3.1 → ebicsclient-1.3.2}/tools/php-parity/generate.php +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ebicsclient
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Pure-Python client for the EBICS 3.0 (H005) banking protocol
|
|
5
5
|
Project-URL: Homepage, https://github.com/schulluk/ebicsclient
|
|
6
6
|
Project-URL: Repository, https://github.com/schulluk/ebicsclient
|
|
@@ -189,6 +189,17 @@ transaction_id = client.upload(PAIN_001, pain001_bytes)
|
|
|
189
189
|
The **certificate-based ("mit Zertifikaten")** profile is a constructor option — see
|
|
190
190
|
[docs/11-certificate-profiles.md](docs/11-certificate-profiles.md).
|
|
191
191
|
|
|
192
|
+
> ### ⚠️ Loading EBICS identifiers from a config file? Quote them.
|
|
193
|
+
>
|
|
194
|
+
> EBICS IDs **can** carry leading zeros (a real Partner ID may look like `00123456`), and
|
|
195
|
+
> ISO message versions look like `"08"`. Unquoted in YAML/JSON/TOML these parse as **numbers** —
|
|
196
|
+
> the wrong type *and* silently stripped of their zeros (PyYAML even reads all-octal-digit
|
|
197
|
+
> values as octal). Since 1.3.1 the library rejects non-string values immediately with an
|
|
198
|
+
> explanatory error, but the correct fix is always **quoting the value in your config**
|
|
199
|
+
> (`partner_id: "00123456"`, `message_version: "08"`) — never wrapping the parsed number in
|
|
200
|
+
> `str()`, which would keep the wrong, zero-stripped identifier and talk to the bank as the
|
|
201
|
+
> wrong subscriber. The same applies to digits-only keyring passphrases.
|
|
202
|
+
|
|
192
203
|
## Documentation index
|
|
193
204
|
|
|
194
205
|
| Doc | Contents |
|
|
@@ -71,6 +71,17 @@ transaction_id = client.upload(PAIN_001, pain001_bytes)
|
|
|
71
71
|
The **certificate-based ("mit Zertifikaten")** profile is a constructor option — see
|
|
72
72
|
[docs/11-certificate-profiles.md](docs/11-certificate-profiles.md).
|
|
73
73
|
|
|
74
|
+
> ### ⚠️ Loading EBICS identifiers from a config file? Quote them.
|
|
75
|
+
>
|
|
76
|
+
> EBICS IDs **can** carry leading zeros (a real Partner ID may look like `00123456`), and
|
|
77
|
+
> ISO message versions look like `"08"`. Unquoted in YAML/JSON/TOML these parse as **numbers** —
|
|
78
|
+
> the wrong type *and* silently stripped of their zeros (PyYAML even reads all-octal-digit
|
|
79
|
+
> values as octal). Since 1.3.1 the library rejects non-string values immediately with an
|
|
80
|
+
> explanatory error, but the correct fix is always **quoting the value in your config**
|
|
81
|
+
> (`partner_id: "00123456"`, `message_version: "08"`) — never wrapping the parsed number in
|
|
82
|
+
> `str()`, which would keep the wrong, zero-stripped identifier and talk to the bank as the
|
|
83
|
+
> wrong subscriber. The same applies to digits-only keyring passphrases.
|
|
84
|
+
|
|
74
85
|
## Documentation index
|
|
75
86
|
|
|
76
87
|
| Doc | Contents |
|
|
@@ -91,6 +91,14 @@ specific return code on `ReturnCodeError`).
|
|
|
91
91
|
- **Gathering** those values from env vars / a vault / Django settings is the **consumer's** job, never the
|
|
92
92
|
library's. Explicit config is auditable; silent environment reads are a surprise and a leakage footgun on a
|
|
93
93
|
money-moving codebase.
|
|
94
|
+
- **Validate at the public boundary, with errors that teach the fix.** Every caller-supplied value is
|
|
95
|
+
type-checked where it enters the library (dataclass `__post_init__`, first line of a public function) —
|
|
96
|
+
never allowed to drift into `lxml`/`cryptography` and die there as a cryptic C-extension error. Learned
|
|
97
|
+
from the field: EBICS identifiers **can** carry leading zeros (`"00123456"`) and versions look like `"08"`;
|
|
98
|
+
unquoted in a consumer's YAML/JSON config they arrive as *numbers* — wrong type **and** silently
|
|
99
|
+
zero-stripped. The error message must therefore say "quote the value in your configuration", because the
|
|
100
|
+
obvious caller "fix" (`str(...)`) would keep a wrong, zero-stripped identifier and address the wrong
|
|
101
|
+
subscriber. See the README's quoting warning and `tests/test_input_validation.py`.
|
|
94
102
|
|
|
95
103
|
## Security (banking client — non-negotiable)
|
|
96
104
|
|
|
@@ -13,7 +13,7 @@ from cryptography.hazmat.primitives.asymmetric import rsa
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _require_identifier(field_name: str, value: object) -> None:
|
|
16
|
-
# EBICS identifiers
|
|
16
|
+
# EBICS identifiers can carry leading zeros (e.g. a Partner ID of "00123456").
|
|
17
17
|
# Loaded from an unquoted YAML/JSON/TOML config value they arrive as numbers — the wrong
|
|
18
18
|
# type AND silently stripped of their zeros (PyYAML even reads all-octal-digit values as
|
|
19
19
|
# octal). Failing here, with the fix in the message, beats a cryptic TypeError four
|
|
@@ -5,7 +5,7 @@ value from an unquoted YAML/JSON config entry) slipping deep into a C extension
|
|
|
5
5
|
surfacing as a cryptic error — as happened live with a numeric ``user_id`` reaching
|
|
6
6
|
``x509.NameAttribute`` (``TypeError: value argument must be a str``). Every boundary must
|
|
7
7
|
fail immediately, with a message that teaches the fix. EBICS identifiers with leading
|
|
8
|
-
zeros (``"
|
|
8
|
+
zeros (``"00123456"``) also *lose their zeros* when parsed as numbers, so the messages
|
|
9
9
|
point at quoting the config value, never at wrapping it in ``str()``.
|
|
10
10
|
"""
|
|
11
11
|
|
|
@@ -40,9 +40,9 @@ def keyring() -> Keyring:
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def test_user_rejects_a_numeric_id_with_a_teaching_message() -> None:
|
|
43
|
-
# The exact bug report: ZKB IDs like "
|
|
43
|
+
# The exact bug report: ZKB IDs like "00123456" unquoted in config arrive as ints.
|
|
44
44
|
with pytest.raises(TypeError) as caught:
|
|
45
|
-
User(partner_id="
|
|
45
|
+
User(partner_id="00123456", user_id=123456) # type: ignore[arg-type]
|
|
46
46
|
message = str(caught.value)
|
|
47
47
|
assert "user_id must be a str" in message
|
|
48
48
|
assert "int" in message
|
|
@@ -173,6 +173,6 @@ def test_the_original_bug_now_fails_at_construction_not_in_cryptography() -> Non
|
|
|
173
173
|
# Regression for the live report: with a numeric user_id the failure must happen at
|
|
174
174
|
# User(...) with our message — never reach x509.NameAttribute inside cryptography.
|
|
175
175
|
with pytest.raises(TypeError) as caught:
|
|
176
|
-
User(partner_id=
|
|
176
|
+
User(partner_id=123456, user_id=123456) # type: ignore[arg-type]
|
|
177
177
|
assert "value argument must be a str" not in str(caught.value)
|
|
178
178
|
assert "leading zeros" in str(caught.value)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|