docs: rewrite README — add ToC, Ansible playbook, disclaimer, full MIT licence
- Table of contents with anchor links - Ansible deploy.yml: clones repo, copies private key, bootstraps store.json via Ansible Vault variables, builds image, runs container; uses creates: guard to preserve live requisitions on re-deploy - AI-generated disclaimer (prominent, at the bottom) - Full MIT licence text (not just the word "MIT") - Improved prose and formatting throughout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2487d8a2f9
commit
e3891f4dc1
305
README.md
305
README.md
@ -1,13 +1,37 @@
|
|||||||
# actual-gocardless-proxy
|
# actual-gocardless-proxy
|
||||||
|
|
||||||
A drop-in [GoCardless Bank Account Data API](https://developer.gocardless.com/bank-account-data/quick-start-guide/) proxy server that lets [Actual Budget](https://actualbudget.org/) sync with French (and other European) bank accounts via [Enable Banking](https://enablebanking.com/) — a **free** PSD2 aggregator.
|
> **AI-generated code — see disclaimer below.**
|
||||||
|
|
||||||
**Zero modifications to actual-server.** The only change is setting one environment variable:
|
A drop-in [GoCardless Bank Account Data API](https://developer.gocardless.com/bank-account-data/quick-start-guide/) proxy that lets [Actual Budget](https://actualbudget.org/) sync with French (and other European) bank accounts via [Enable Banking](https://enablebanking.com/) — a **free** PSD2 aggregator.
|
||||||
|
|
||||||
|
**Zero modifications to actual-server.** The only change required is one environment variable:
|
||||||
|
|
||||||
```
|
```
|
||||||
GOCARDLESS_BASE_URL=http://gocardless-proxy:3456
|
GOCARDLESS_BASE_URL=http://gocardless-proxy:3456
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
1. [How it works](#how-it-works)
|
||||||
|
2. [Setup](#setup)
|
||||||
|
- [1. Sign up for Enable Banking](#1-sign-up-for-enable-banking)
|
||||||
|
- [2. Generate an RSA key pair](#2-generate-an-rsa-key-pair)
|
||||||
|
- [3. Run the setup script](#3-run-the-setup-script)
|
||||||
|
- [4. Add the proxy to docker-compose](#4-add-the-proxy-to-docker-compose)
|
||||||
|
- [5. Start the services](#5-start-the-services)
|
||||||
|
- [6. Configure Actual Budget](#6-configure-actual-budget)
|
||||||
|
3. [Ansible deployment](#ansible-deployment)
|
||||||
|
4. [OAuth redirect flow](#oauth-redirect-flow)
|
||||||
|
5. [Supported banks](#supported-banks)
|
||||||
|
6. [Troubleshooting](#troubleshooting)
|
||||||
|
7. [Data & privacy](#data--privacy)
|
||||||
|
8. [Disclaimer](#disclaimer)
|
||||||
|
9. [License](#license)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -15,15 +39,15 @@ Actual Budget (browser)
|
|||||||
│ GoCardless API calls
|
│ GoCardless API calls
|
||||||
▼
|
▼
|
||||||
actual-server
|
actual-server
|
||||||
│ GOCARDLESS_BASE_URL → http://gocardless-proxy:3456
|
│ GOCARDLESS_BASE_URL=http://gocardless-proxy:3456
|
||||||
▼
|
▼
|
||||||
gocardless-proxy ◄── this repo
|
gocardless-proxy ◄── this repo
|
||||||
│ Enable Banking PSD2 API
|
│ Enable Banking PSD2 API (RS256 JWT auth)
|
||||||
▼
|
▼
|
||||||
Enable Banking → French banks (BNP, SG, CA, LCL, BP, …)
|
Enable Banking → French banks (BNP, SG, CA, LCL, BP, …)
|
||||||
```
|
```
|
||||||
|
|
||||||
The proxy translates GoCardless API shapes ↔ Enable Banking shapes on the fly and persists all state (tokens, requisitions, account mappings) in `./data/store.json` so Docker restarts don't break existing account links.
|
The proxy translates GoCardless API shapes ↔ Enable Banking shapes on the fly. All state (tokens, requisitions, account mappings) is persisted in `./data/store.json` so Docker restarts do not break existing Actual Budget account links.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -31,53 +55,49 @@ The proxy translates GoCardless API shapes ↔ Enable Banking shapes on the fly
|
|||||||
|
|
||||||
### 1. Sign up for Enable Banking
|
### 1. Sign up for Enable Banking
|
||||||
|
|
||||||
Go to [enablebanking.com](https://enablebanking.com) and create a **free personal account**. Under your app settings, note your **Application ID**.
|
Go to [enablebanking.com](https://enablebanking.com) and create a **free personal account**. Under your application settings, note your **Application ID**.
|
||||||
|
|
||||||
### 2. Generate an RSA key pair
|
### 2. Generate an RSA key pair
|
||||||
|
|
||||||
Enable Banking uses RS256 JWT auth. You need to provide your **public key** in the Enable Banking dashboard and keep the **private key** on your server.
|
Enable Banking authenticates API calls with an RS256 JWT signed by your application's private key. You upload the public key to Enable Banking; the private key stays on your server.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generate a 2048-bit RSA private key in PKCS8 format
|
# Generate a PKCS8 RSA private key
|
||||||
openssl genpkey -algorithm RSA -pkcs8 -out private_key.pem -pkeyopt rsa_keygen_bits:2048
|
openssl genpkey -algorithm RSA -pkcs8 -out private_key.pem -pkeyopt rsa_keygen_bits:2048
|
||||||
|
|
||||||
# Extract the public key (upload this to Enable Banking)
|
# Extract the public key — upload this to the Enable Banking dashboard
|
||||||
openssl pkey -in private_key.pem -pubout -out public_key.pem
|
openssl pkey -in private_key.pem -pubout -out public_key.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
Upload `public_key.pem` in the Enable Banking dashboard under your application's API settings.
|
Store `private_key.pem` securely. You will reference it during setup.
|
||||||
|
|
||||||
Keep `private_key.pem` somewhere safe — you'll need it in the next step.
|
|
||||||
|
|
||||||
### 3. Run the setup script
|
### 3. Run the setup script
|
||||||
|
|
||||||
Clone this repo and install dependencies:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/yourname/actual-gocardless-proxy
|
git clone https://github.com/yourname/actual-gocardless-proxy
|
||||||
cd actual-gocardless-proxy
|
cd actual-gocardless-proxy
|
||||||
npm install
|
npm install
|
||||||
```
|
|
||||||
|
|
||||||
Run the interactive setup:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run setup
|
npm run setup
|
||||||
```
|
```
|
||||||
|
|
||||||
The script will ask for:
|
The script prompts for:
|
||||||
- Your Enable Banking **Application ID**
|
|
||||||
- Path to your **private key PEM** file
|
|
||||||
- The **proxy base URL** (the URL that Enable Banking will redirect to after OAuth — must be reachable from your browser; e.g. `http://localhost:3456` for local dev or `https://yourserver.example.com` for production)
|
|
||||||
|
|
||||||
It will generate a random `secret_id` and `secret_key` pair and print them:
|
| Prompt | Example |
|
||||||
|
|--------|---------|
|
||||||
|
| Enable Banking Application ID | `abc123-...` |
|
||||||
|
| Path to private key PEM | `/home/user/private_key.pem` |
|
||||||
|
| Proxy base URL | `https://yourserver.example.com` or `http://localhost:3456` |
|
||||||
|
|
||||||
|
The proxy base URL is the address Enable Banking redirects to after OAuth — it **must be reachable from the user's browser**, not just from within Docker.
|
||||||
|
|
||||||
|
On completion the script prints:
|
||||||
|
|
||||||
```
|
```
|
||||||
──────────────────────────────────────────────────────────
|
──────────────────────────────────────────────────────────
|
||||||
Enter these values in Actual Budget → Settings → GoCardless:
|
Enter these values in Actual Budget → Settings → GoCardless:
|
||||||
|
|
||||||
Secret ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
Secret ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
Secret Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
Secret Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
And set this environment variable on actual-server:
|
And set this environment variable on actual-server:
|
||||||
|
|
||||||
@ -85,26 +105,26 @@ And set this environment variable on actual-server:
|
|||||||
──────────────────────────────────────────────────────────
|
──────────────────────────────────────────────────────────
|
||||||
```
|
```
|
||||||
|
|
||||||
All credentials are stored in `./data/store.json`.
|
All credentials are written to `./data/store.json`.
|
||||||
|
|
||||||
### 4. Add the proxy to your docker-compose.yml
|
### 4. Add the proxy to docker-compose
|
||||||
|
|
||||||
In your existing `actual-server` `docker-compose.yml`, add the proxy service and wire it to actual-server:
|
Paste the `gocardless-proxy` service block into your existing `actual-server` `docker-compose.yml` and add `GOCARDLESS_BASE_URL` to actual-server:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
actual-server:
|
actual-server:
|
||||||
image: actualbudget/actual-server:latest
|
image: actualbudget/actual-server:latest
|
||||||
# ... your existing config ...
|
|
||||||
environment:
|
environment:
|
||||||
GOCARDLESS_BASE_URL: http://gocardless-proxy:3456
|
GOCARDLESS_BASE_URL: http://gocardless-proxy:3456
|
||||||
# ... your other env vars ...
|
# ... rest of your actual-server env vars
|
||||||
depends_on:
|
depends_on:
|
||||||
- gocardless-proxy
|
- gocardless-proxy
|
||||||
|
|
||||||
gocardless-proxy:
|
gocardless-proxy:
|
||||||
build: /path/to/actual-gocardless-proxy
|
build: /path/to/actual-gocardless-proxy
|
||||||
# or: image: ghcr.io/yourname/actual-gocardless-proxy:latest
|
# or use a pre-built image:
|
||||||
|
# image: ghcr.io/yourname/actual-gocardless-proxy:latest
|
||||||
container_name: gocardless-proxy
|
container_name: gocardless-proxy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
@ -113,7 +133,7 @@ services:
|
|||||||
PORT: 3456
|
PORT: 3456
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note on PROXY_BASE_URL:** The proxy base URL is saved in `data/store.json` during setup. If you need to change it later (e.g. you added a reverse proxy), re-run `npm run setup` or edit `data/store.json` directly and update `config.proxy_base_url`.
|
> **Changing the proxy base URL later:** Re-run `npm run setup`, or edit `config.proxy_base_url` directly in `data/store.json` and restart the container.
|
||||||
|
|
||||||
### 5. Start the services
|
### 5. Start the services
|
||||||
|
|
||||||
@ -121,45 +141,176 @@ services:
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify the proxy is running:
|
Verify the proxy is up:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://localhost:3456/health
|
curl http://localhost:3456/health
|
||||||
# → {"status":"ok","configured":true}
|
# {"status":"ok","configured":true}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. Configure Actual Budget
|
### 6. Configure Actual Budget
|
||||||
|
|
||||||
In Actual Budget, go to **Settings → GoCardless** and enter the `secret_id` and `secret_key` printed in step 3.
|
Go to **Settings → GoCardless** in Actual Budget and enter the `Secret ID` and `Secret Key` printed in step 3. Then link your bank via **Accounts → Link account**.
|
||||||
|
|
||||||
You can now go to **Accounts → Link account** and search for your French bank.
|
---
|
||||||
|
|
||||||
|
## Ansible deployment
|
||||||
|
|
||||||
|
The playbook below deploys the proxy to a remote host that already runs `actual-server` via Docker Compose. Adjust variables at the top to match your environment.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# deploy.yml
|
||||||
|
---
|
||||||
|
- name: Deploy actual-gocardless-proxy
|
||||||
|
hosts: actual_host
|
||||||
|
become: true
|
||||||
|
|
||||||
|
vars:
|
||||||
|
proxy_dir: /opt/actual-gocardless-proxy
|
||||||
|
data_dir: /opt/actual-gocardless-proxy/data
|
||||||
|
proxy_port: 3456
|
||||||
|
# Set proxy_base_url to the URL reachable from the user's browser
|
||||||
|
proxy_base_url: "https://actual.example.com"
|
||||||
|
eb_app_id: "{{ vault_eb_app_id }}"
|
||||||
|
eb_private_key_src: "{{ playbook_dir }}/files/private_key.pem"
|
||||||
|
gc_secret_id: "{{ vault_gc_secret_id }}"
|
||||||
|
gc_secret_key: "{{ vault_gc_secret_key }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Install git and Docker dependencies
|
||||||
|
ansible.builtin.package:
|
||||||
|
name:
|
||||||
|
- git
|
||||||
|
- python3-docker
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Clone / update repository
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: https://github.com/yourname/actual-gocardless-proxy.git
|
||||||
|
dest: "{{ proxy_dir }}"
|
||||||
|
version: main
|
||||||
|
force: true
|
||||||
|
|
||||||
|
- name: Create data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ data_dir }}"
|
||||||
|
state: directory
|
||||||
|
mode: "0700"
|
||||||
|
|
||||||
|
- name: Copy RSA private key
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ eb_private_key_src }}"
|
||||||
|
dest: "{{ data_dir }}/private_key.pem"
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Write store.json (credentials + proxy config)
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ data_dir }}/store.json"
|
||||||
|
mode: "0600"
|
||||||
|
content: |
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"eb_app_id": "{{ eb_app_id }}",
|
||||||
|
"eb_private_key": {{ lookup('file', eb_private_key_src) | to_json }},
|
||||||
|
"gc_secret_id": "{{ gc_secret_id }}",
|
||||||
|
"gc_secret_key": "{{ gc_secret_key }}",
|
||||||
|
"proxy_base_url": "{{ proxy_base_url }}"
|
||||||
|
},
|
||||||
|
"gc_tokens": {},
|
||||||
|
"institutions_cache": null,
|
||||||
|
"institutions_cache_at": 0,
|
||||||
|
"agreements": {},
|
||||||
|
"requisitions": {},
|
||||||
|
"accounts": {}
|
||||||
|
}
|
||||||
|
# Skip this task if store.json already exists (preserves live state:
|
||||||
|
# tokens, requisitions, linked accounts). Remove the condition if you
|
||||||
|
# want to reset credentials on every deploy.
|
||||||
|
args:
|
||||||
|
creates: "{{ data_dir }}/store.json"
|
||||||
|
|
||||||
|
- name: Build proxy Docker image
|
||||||
|
community.docker.docker_image:
|
||||||
|
name: actual-gocardless-proxy
|
||||||
|
tag: local
|
||||||
|
build:
|
||||||
|
path: "{{ proxy_dir }}"
|
||||||
|
source: build
|
||||||
|
force_source: true
|
||||||
|
|
||||||
|
- name: Run gocardless-proxy container
|
||||||
|
community.docker.docker_container:
|
||||||
|
name: gocardless-proxy
|
||||||
|
image: actual-gocardless-proxy:local
|
||||||
|
restart_policy: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:{{ proxy_port }}:{{ proxy_port }}"
|
||||||
|
volumes:
|
||||||
|
- "{{ data_dir }}:/app/data"
|
||||||
|
env:
|
||||||
|
PORT: "{{ proxy_port | string }}"
|
||||||
|
STORE_PATH: /app/data/store.json
|
||||||
|
|
||||||
|
- name: Ensure actual-server has GOCARDLESS_BASE_URL set
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: >
|
||||||
|
Remember to add
|
||||||
|
GOCARDLESS_BASE_URL=http://gocardless-proxy:{{ proxy_port }}
|
||||||
|
to your actual-server environment and restart it.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sensitive variables** (`eb_app_id`, `gc_secret_id`, `gc_secret_key`) should be stored in an Ansible Vault file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create vault file
|
||||||
|
ansible-vault create group_vars/actual_host/vault.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/actual_host/vault.yml
|
||||||
|
vault_eb_app_id: "your-enable-banking-app-id"
|
||||||
|
vault_gc_secret_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||||
|
vault_gc_secret_key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the playbook:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook deploy.yml --ask-vault-pass
|
||||||
|
```
|
||||||
|
|
||||||
|
> **First deploy only:** `store.json` is written with `creates:` so it is not overwritten on subsequent runs — this preserves live requisitions and linked accounts. On a brand-new host the credentials are bootstrapped automatically; no need to run `npm run setup` manually.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## OAuth redirect flow
|
## OAuth redirect flow
|
||||||
|
|
||||||
```
|
```
|
||||||
1. actual-server POST /api/v2/requisitions/ { redirect: "http://actual:5006/..." }
|
1. actual-server POST /api/v2/requisitions/
|
||||||
|
body: { redirect: "http://actual:5006/...", institution_id }
|
||||||
↓
|
↓
|
||||||
2. proxy POST https://api.enablebanking.com/auth
|
2. proxy POST https://api.enablebanking.com/auth
|
||||||
{ aspsp: { name, country }, redirect_url: "http://proxy/callback",
|
{ aspsp: { name, country },
|
||||||
|
redirect_url: "http://proxy/callback",
|
||||||
state: <requisition_id> }
|
state: <requisition_id> }
|
||||||
← { url: "https://tilisy.enablebanking.com/..." }
|
← { url: "https://tilisy.enablebanking.com/..." }
|
||||||
↓
|
↓
|
||||||
3. proxy returns requisition with link = EB auth URL
|
3. proxy returns requisition { id, status: "CR", link: <EB auth URL> }
|
||||||
↓
|
↓
|
||||||
4. User visits the link, authenticates at their bank
|
4. User visits the link, authenticates at their bank
|
||||||
↓
|
↓
|
||||||
5. Enable Banking redirects → http://proxy/callback?code=xxx&state=<req_id>
|
5. Enable Banking → http://proxy/callback?code=xxx&state=<requisition_id>
|
||||||
↓
|
↓
|
||||||
6. proxy POST https://api.enablebanking.com/sessions { code }
|
6. proxy POST https://api.enablebanking.com/sessions { code }
|
||||||
← { session_id, accounts: [uid, ...] }
|
← { session_id, accounts: [uid, ...] }
|
||||||
→ fetches account details, stores GC account IDs
|
→ fetches account details per UID
|
||||||
→ marks requisition status "LN" (linked)
|
→ stores gc_id ↔ eb_uid mapping in store.json
|
||||||
→ redirects → http://actual:5006/...?requisition_id=<req_id>
|
→ sets requisition status "LN" (linked)
|
||||||
|
→ 302 → http://actual:5006/...?requisition_id=<req_id>
|
||||||
↓
|
↓
|
||||||
7. actual-server GET /api/v2/requisitions/<req_id>/
|
7. actual-server GET /api/v2/requisitions/<req_id>/
|
||||||
← { status: "LN", accounts: ["gc-acc-id-1", ...] }
|
← { status: "LN", accounts: ["gc-uuid-1", ...] }
|
||||||
↓
|
↓
|
||||||
8. actual-server GET /api/v2/accounts/<id>/details/
|
8. actual-server GET /api/v2/accounts/<id>/details/
|
||||||
GET /api/v2/accounts/<id>/balances/
|
GET /api/v2/accounts/<id>/balances/
|
||||||
@ -187,27 +338,27 @@ All French banks supported by Enable Banking, including:
|
|||||||
| Fortuneo | FTNOFRP1 |
|
| Fortuneo | FTNOFRP1 |
|
||||||
| Hello bank! | BNPAFRPP |
|
| Hello bank! | BNPAFRPP |
|
||||||
|
|
||||||
See [enablebanking.com/docs/markets/fr/](https://enablebanking.com/docs/markets/fr/) for the full list.
|
See [enablebanking.com/docs/markets/fr/](https://enablebanking.com/docs/markets/fr/) for the complete list.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### "Proxy not configured" error
|
**"Proxy not configured" error**
|
||||||
Run `npm run setup` and restart the container.
|
Run `npm run setup` and restart the container.
|
||||||
|
|
||||||
### "Unknown institution_id" when creating a requisition
|
**"Unknown institution_id" when linking an account**
|
||||||
actual-server caches institutions. Go to **Settings → GoCardless → Reset** and re-fetch banks.
|
actual-server caches the institutions list. Go to **Settings → GoCardless → Reset** and re-fetch.
|
||||||
|
|
||||||
### OAuth callback fails with "Enable Banking error"
|
**OAuth callback fails with "Enable Banking error"**
|
||||||
- Make sure `proxy_base_url` in `data/store.json` is reachable from your browser (not just from Docker).
|
- `proxy_base_url` in `data/store.json` must be reachable from your browser, not just from inside Docker.
|
||||||
- Check that the redirect URL is whitelisted in your Enable Banking application settings.
|
- Make sure the callback URL (`{proxy_base_url}/callback`) is whitelisted in your Enable Banking application settings.
|
||||||
|
|
||||||
### Transactions not appearing
|
**Transactions not appearing**
|
||||||
Enable Banking may return an empty `transactions` array for accounts with no activity in the requested date range. Try widening the date range.
|
Enable Banking may return an empty array if no transactions fall in the requested date range. Try widening the range in Actual Budget.
|
||||||
|
|
||||||
### Private key errors
|
**Private key parse error**
|
||||||
Make sure the key is **PKCS8** format. To convert from traditional RSA format:
|
The key must be in **PKCS8** format. To convert from a traditional RSA key:
|
||||||
```bash
|
```bash
|
||||||
openssl pkcs8 -topk8 -nocrypt -in old_key.pem -out private_key.pem
|
openssl pkcs8 -topk8 -nocrypt -in old_key.pem -out private_key.pem
|
||||||
```
|
```
|
||||||
@ -216,12 +367,46 @@ openssl pkcs8 -topk8 -nocrypt -in old_key.pem -out private_key.pem
|
|||||||
|
|
||||||
## Data & privacy
|
## Data & privacy
|
||||||
|
|
||||||
All bank credentials and tokens stay on your server inside `./data/store.json`. Nothing is sent to any third party except Enable Banking (which is the PSD2 provider) and your bank.
|
All credentials and session data are stored locally in `./data/store.json`. No data is sent to any third party other than Enable Banking (the licensed PSD2 provider) and your bank.
|
||||||
|
|
||||||
The `data/` directory is git-ignored and should not be committed.
|
The `data/` directory is git-ignored and must not be committed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
**This project was entirely generated by an AI assistant (Claude, by Anthropic) without manual code authorship.**
|
||||||
|
|
||||||
|
It has not been independently audited, penetration-tested, or validated against production bank APIs. Use it at your own risk. In particular:
|
||||||
|
|
||||||
|
- The Enable Banking integration is based on publicly available documentation and may require adjustments as the API evolves.
|
||||||
|
- No warranty is given regarding correctness, security, or fitness for any purpose.
|
||||||
|
- Your bank credentials and PSD2 access tokens are handled by this software — review the code before deploying in a sensitive environment.
|
||||||
|
|
||||||
|
Contributions, corrections, and reviews from human developers are very welcome.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user