Budget Tracker

The bank list

This is the file the app fetches when you turn bank list updates on. It describes how to read each bank's alert emails. It is the same file for everyone and contains nothing about anybody.

The files

Both are plain text on purpose. You should be able to read what your phone accepted without needing a tool for it.

What is in it

For each bank: the email address its alerts come from, the subject line to look for, and the patterns that pull out the amount, the card and the shop. That is the whole file. There are no user accounts in it, no addresses, no transaction data — it is a description of email formats.

How the signature works

The signature covers the exact bytes of patterns.json. The app carries the matching public key and checks the signature before it reads the file at all. A list that has been altered, substituted, or served by somebody else does not verify, and the app keeps the list it already had.

Three more things the app checks, because a valid signature alone is not enough:

Checking it yourself

The signature is Ed25519 over the file's bytes. The public key is published here, because a key you have to go and find is a check nobody makes:

key_id  6071f4a8
public  Lcc1ZWO/D2wVG3o7Y8yPNZ2s/7uRDS6M+c9djfTLOfw=

The same key id appears on the app's About screen, so you can confirm the phone is checking against the key published here and not something else.

curl -sO https://budget-tracker.sahadeosolutions.ca/patterns.json
curl -sO https://budget-tracker.sahadeosolutions.ca/patterns.json.sig

python3 - <<'PY'
import base64
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
key = Ed25519PublicKey.from_public_bytes(
    base64.b64decode("Lcc1ZWO/D2wVG3o7Y8yPNZ2s/7uRDS6M+c9djfTLOfw="))
sig = [l.split(":", 1)[1].strip()
       for l in open("patterns.json.sig") if l.startswith("signature")][0]
key.verify(base64.b64decode(sig), open("patterns.json", "rb").read())
print("verified")
PY

Two keys can be trusted by the app at once, so one can be replaced without every phone having to update on the same day. If the key above ever changes, the old one keeps working until the app that trusts only the new one has shipped.

Because the signature covers the exact bytes, reformatting the file — even adding a newline — will make it stop verifying. That is deliberate: it means there is no gap between the thing that was checked and the thing the app reads.