K0 spike: local Enable Banking test app
Stdlib Python app (docs/spikes/k0/app.py) on localhost:8765: lists Swedish ASPSPs, starts BankID authorisation with the registered https redirect and a paste box for the landed address, creates the session, fetches transactions with and without PSU headers (continuation_key paging), balances, diff between fetches and an aggregate analysis block. Key and state in the git-ignored docs/spikes/k0/.local/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,8 @@ infra/dev/backups/
|
|||||||
*.sqlite.gz
|
*.sqlite.gz
|
||||||
*.sqlite-wal
|
*.sqlite-wal
|
||||||
*.sqlite-shm
|
*.sqlite-shm
|
||||||
|
# K0 spike (docs/spikes/k0): Enable Banking key, session and fetched transactions
|
||||||
|
/docs/spikes/k0/.local/
|
||||||
# Web client (web/): dependencies and build output
|
# Web client (web/): dependencies and build output
|
||||||
web/node_modules/
|
web/node_modules/
|
||||||
web/dist/
|
web/dist/
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# K0 spike: local Enable Banking test app
|
||||||
|
|
||||||
|
A one-file local web app that connects a card account (SJ Prio Mastercard, SEB Kort Bank AB) through Enable Banking with BankID and shows what the API returns. Python 3 standard library only; the RS256 JWT is signed with `openssl`.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 docs/spikes/k0/app.py # serves http://localhost:8765/ and opens the browser
|
||||||
|
```
|
||||||
|
|
||||||
|
Options: `--port`, `--no-browser`, `--local-dir` (config and state folder), `--api-base` (a fake API for tests).
|
||||||
|
|
||||||
|
## Where the key goes
|
||||||
|
|
||||||
|
`docs/spikes/k0/.local/` (git-ignored, created on first run):
|
||||||
|
|
||||||
|
* `<application-id>.pem`: the private key the Enable Banking control panel downloaded at registration (the file name is the application id).
|
||||||
|
* `config.json` (optional): `{"application_id": "…", "key_file": "….pem"}` when the file name is not the id or there are several keys.
|
||||||
|
* `state.json`: written by the app. Holds the settings, the bank list, the session id, the account, the last two fetches and an aggregate fetch log. When you run it again it reuses the session, so you do not need BankID again until `valid_until`.
|
||||||
|
|
||||||
|
## What each button tests
|
||||||
|
|
||||||
|
| Section | Button | Call | What it shows |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 Status | none | none | Application id, key, session with `valid_until` and days left, chosen account |
|
||||||
|
| 2 Banker | Lista banker / Välj bank | `GET /aspsps?country=SE` | All Swedish ASPSPs. SJ, SEB Kort and Eurocard are highlighted and sorted first. Per row: `beta`, `maximum_consent_validity`, `psu_types`, `auth_methods`, `required_psu_headers`. The chosen ASPSP's full JSON is shown below. The default is the one named "SJ Prio" |
|
||||||
|
| 3 Anslut | Anslut med BankID | `POST /auth` | Sets `valid_until` to now plus the ASPSP's maximum, capped at 180 days, less 5 min, with `psu_type: personal` and a random `state`. Opens the bank in a new tab, where you scan the QR with BankID |
|
||||||
|
| 4 Klistra in | Använd adressen | `POST /sessions` | Takes `code` and `state` from any pasted address and checks `state`. This is the main path: the redirect goes to `https://kvitt.suorra.duckdns.org/cards/callback`, which does not load, but the address bar still carries the code |
|
||||||
|
| 5 Konton | Kontrollera session / Välj konto | `GET /sessions/{id}` | Accounts with uid, name, product, currency and type. Identifiers are masked to the last 4 characters. If there is only one account (or one CARD account), it is chosen by default |
|
||||||
|
| 6 Hämta | Uppdatera | `GET /accounts/{uid}/transactions` | Sends PSU headers (user present): always `Psu-Ip-Address` and `Psu-User-Agent`, plus every header the ASPSP lists in `required_psu_headers`. Uses `date_from` = today − history days, optionally `strategy=longest`, and follows `continuation_key` |
|
||||||
|
| 6 Hämta | Bakgrundshämtning | same, without PSU headers | Tests the background path. A refusal is shown with its HTTP status and error JSON |
|
||||||
|
| 6 Hämta | Saldo | `GET /accounts/{uid}/balances` | Balances, fetched with PSU headers |
|
||||||
|
| 7 Köp | none | none | Purchases with both dates, text, signed amount, currency, direction, status, `entry_reference` and a "rå" toggle for the raw JSON. Compared with the previous fetch: new rows, changed rows (PDNG→BOOK) and rows that disappeared |
|
||||||
|
| 8 Analys | Kopiera analys | none | Aggregates only: counts, dates reached vs requested, field presence, non-SEK rows, `entry_reference` presence and stability, PDNG→BOOK matched by `entry_reference` vs by amount+date (±7 days), pages per fetch, and the fetch log |
|
||||||
|
| 9 Koppla från | Koppla från | `DELETE /sessions/{id}` | Clears the local session, accounts and transactions. Keeps the settings, the bank list and the aggregate log |
|
||||||
|
|
||||||
|
The PSU IP address field is filled from `api.ipify.org` on the first Uppdatera if you leave it empty; you can also type an address. `http://localhost:8765/callback` is handled as well, but Enable Banking's control panel refuses `http` redirect URLs, so it is not the default.
|
||||||
|
|
||||||
|
## Privacy
|
||||||
|
|
||||||
|
stdout shows only method, path template and HTTP status. It never shows bodies, merchant texts, amounts or ids. Personal data stays in `.local/`. Copy only the Analys block into reports.
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user