Skip to content

Release v26.09

Latest

Choose a tag to compare

@ShahanaFarooqui ShahanaFarooqui released this 29 Sep 19:24

cln-application 26.09

This release moves the application to Node 22, adds optional native HTTPS and reverse-proxy support, tightens how settings, passwords and sessions are handled, and modernises the build and CI pipeline. Nothing in the UI changes shape; most of the work is under the hood.

Highlights

  • Optional native HTTPS. Set APP_TLS_KEY_FILE and APP_TLS_CERT_FILE to serve TLS directly, or keep a reverse proxy in front as before. The README now explains the three supported transport setups and what APP_PROTOCOL means.
  • Reverse-proxy aware. New APP_TRUST_PROXY setting (false, true, a hop count or a list of proxy addresses) controls which X-Forwarded-* headers are honoured.
  • Node 22. The Docker image, the CI workflows and the runtime now run on Node 22; the root package.json declares engines.node >= 20.
  • Backend unit tests. A first suite covers authentication, settings validation and request protection, and runs in CI alongside the frontend tests.

Application

  • New passwords must be at least 12 characters and different from the current one; the form says so.
  • The "Confirm New Password" field must be typed; pasted or dropped text is ignored there, so a typo in the new password cannot be confirmed by pasting the same wrong value.
  • Changing the password signs out every other open session. Logging out ends the session on the server as well as in the browser.
  • Application settings are validated before they are saved; invalid values return a clear 400 response listing the accepted options.
  • Fiat exchange rates are fetched only after sign-in and cached for five minutes.
  • Creating an invoice rune from the Connect Wallet screen is idempotent: a second attempt answers 409 instead of adding another entry.
  • Error responses are consistent: 400 for malformed JSON, 413 for bodies over 500 kB, and a generic 500 for unexpected failures. Node error messages still pass through for lightning calls.
  • Commando connections use the ws client on every Node version and reconnect on demand instead of giving up after a few attempts.
  • gRPC protocol definitions ship with the backend instead of being fetched at start-up.
  • Startup logs describe the transport configuration and whether single sign-on mode is active.
  • Opening another application on the same hostname, such as Ride The Lightning, no longer breaks the session check. The CSRF cookie has its own name and the client never lets a foreign XSRF-TOKEN cookie replace its token (#165). If the session check does fail, the login dialog now shows the actual reason instead of implying a wrong password.
  • Large satoshi balances in the summary boxes read in millions instead of thousands: 1,250,000 sats now shows as 1.25M rather than 1,250K, and anything under a million is shown in full (#158). BTC display is unchanged.
  • Paying a BOLT 12 offer now checks the invoice returned by the issuer against the amount shown in the form. If the issuer asks for a different amount, the payment is not sent and both amounts are shown.
  • The invoice rune created from the Connect Wallet screen now allows invoice and listinvoices as alternatives within one restriction, so wallets that receive it can actually use it. A rune created by an earlier version could not authorize either call; see Upgrade notes.
  • The first password of a fresh install can only be set from the server's own address: localhost, an IP address, the configured APP_HOST, or a .local / .onion name. Logins and later password changes work from any address as before.
  • API responses are sent with Cache-Control: no-store, so nothing returned by the API stays in the browser cache after logout.
  • Logging out waits for the server to end the session before clearing the screen; if the request fails, the session view stays open and the error is shown.
  • The server parses JSON request bodies only.

Container, build and CI

  • Base images are pinned by digest; the frontend build inside the image emits no source maps and no inline runtime script.
  • .dockerignore keeps the build context small; apt caches are cleaned in both stages.
  • GitHub Actions are pinned by commit, every workflow declares its permissions, and a weekly job runs a dependency audit and a secret scan.
  • Release images are published with provenance and SBOM attestations. Dependabot proposes updates for npm, Docker and GitHub Actions.
  • csurf is replaced by csrf-csrf, helmet sets the response headers, and the unused ts-node dependency is gone. All runtime dependencies are at their latest versions with a clean audit.
  • The development compose file is a hard-coded regtest example with all data under /tmp.
  • The runtime image carries the real package-lock.json; earlier images held a copy of package.json under that name.

Platform notes

  • StartOS. Keep APP_PROTOCOL=https and leave APP_TLS_KEY_FILE and APP_TLS_CERT_FILE empty; the platform proxy terminates TLS and the app still listens on plain HTTP behind it. config.json keeps the same keys, but after the first login the password value changes from a 64-character hex string to a longer scrypt$… string; a package that validates that file must keep treating password as an opaque string. Nothing else is written to the file. If the package also exposes the UI over a plain-HTTP Tor address, verify login there once: cookies are now marked Secure whenever APP_PROTOCOL=https, and a browser accepts them only on origins it treats as secure. New installs set the first password through the platform's .local or .onion address, which the first-password rule accepts, so nothing changes there.
  • Umbrel. No configuration change is needed. The app keeps running in single sign-on mode behind the Umbrel proxy; two new lines appear in its logs at startup, one saying single sign-on is on and one saying the app is served over plain HTTP on a non-loopback address. Both are expected on Umbrel and can be ignored. The image is multi-architecture (amd64, arm64, arm/v7) as before. Running Ride The Lightning alongside on the same hostname no longer breaks the session (#165). The first-password rule for new installs does not apply here: single sign-on has no password screen.
  • Standalone Docker. Pull the new image; the docker run invocation, the mounted config.json and the commando env file are unchanged. If a reverse proxy sits in front, set APP_PROTOCOL=https and point APP_TRUST_PROXY at the proxy. On a fresh install, set the first password by opening the app via localhost, its IP address or the name in APP_HOST; a custom DNS name works for everything after that.
  • Bare metal. Run on Node 22 (the tested runtime; engines allows 20 or newer) and install with npm ci under the same Node you run with. New environment variables are optional: APP_TRUST_PROXY, APP_TLS_KEY_FILE, APP_TLS_CERT_FILE. The same first-password rule applies as for Docker.

Upgrade notes

  • Passwords. Existing installs keep working. A password stored by an earlier version is converted to a salted hash on the first successful login.
  • APP_PROTOCOL=https describes what the browser sees. Set it only when TLS is actually in front of the app (a proxy or the new native option), otherwise cookies will not be accepted.
  • Body size. Requests larger than 500 kB are rejected.
  • CSRF cookie name. The cookie is now cln_csrf; the header stays X-XSRF-TOKEN. Custom clients that read the old _csrf cookie by name must update.
  • New environment variables. APP_TRUST_PROXY (default false), APP_TLS_KEY_FILE, APP_TLS_CERT_FILE (default empty).
  • First password. On a fresh install the first password is accepted only when the app is opened via localhost, an IP address, APP_HOST, or a .local / .onion name. Existing installs are not affected.
  • Invoice rune. If you created an invoice rune from the Connect Wallet screen with an earlier version, it cannot be used by wallets. Remove the INVOICE_RUNE line from the commando env file, restart, and create a new one from the Connect Wallet screen; the old rune can be blacklisted on the node with blacklistrune.
  • JSON only. Custom clients must send application/json bodies; form-encoded bodies are no longer parsed.