Commit graph

1346 commits

Author SHA1 Message Date
Suheb
a005b687a7
Release 0.15.10 (#1665)
* Update version 0.15.10

* Update project dependencies to resolve Dependabot security alerts

Applies the fixes from the open Dependabot PRs (#1648, #1649, #1650) in a
single pass on the release branch, regenerating the lockfile from scratch.

axios 1.16.0 -> 1.18.1 was the only production exposure (10 advisories).
Transitive deps moved to their fixed in-range versions (fast-uri 3.1.4,
form-data, qs, tough-cookie, tar, del, globby); dev toolchain took safe
bumps (nodemon 3.1.14, eslint 9.39.5, @typescript-eslint 8.65.0).

Drops the unused protractor devDependency: no e2e directory, no config and
no e2e target in angular.json, but 100 packages and the deprecated request
stack behind it. That clears both critical advisories.

npm audit: 50 (2 critical) -> 29 (0 critical); production deps 1 -> 0.
Remaining findings are dev-only tooling needing an Angular 21 migration
rather than a version bump.

Verified: lint, 204 frontend specs, backend + frontend production builds,
and 19 API checks against the docker regtest fixture covering LND, Core
Lightning and Eclair (getinfo, channels, peers, invoices, payments and
forwarding history).

* Fill in PR number in release note (#1653)

* Harden login request validation (#1654)

Tightens server-side validation of authentication requests, guards the password-reset route behind an authenticated session, and wires the backend regression suite (test/backend/) into npm run test. Users with two-factor authentication enabled are encouraged to update promptly.

Verified: backend specs 12/12, lint green, frontend specs 204/204, and the full authentication matrix end-to-end on the docker regtest fixture.

* Reduce exposure of authentication secrets in logs and config responses (#1659)

* Reduce exposure of authentication secrets in logs and config responses

* Fill in PR number in release note (#1659)

* Harden redaction helpers and secret restore paths

* Pin deployment auth switches server-side and harden settings persistence

* Contain backup file reads and harden config persistence

* Pin backup containment root and preserve config file mode on save

* Update Angular framework packages to 20.3.27 (#1661)

* Update Angular framework packages to 20.3.27

Batches the three Dependabot PRs open against master for the Angular framework
(@angular/core #1658, @angular/compiler #1657, @angular/common #1655) into one
update on the release branch. The framework packages are pinned to exact
versions and their peer ranges require them to move together, so all nine
20.3.26 packages go to 20.3.27: animations, common, compiler, compiler-cli,
core, forms, platform-browser, platform-browser-dynamic and router.

Patch-level upstream fixes only, no advisories. The update stays inside Angular
20 - @angular/build and @angular/cli (20.3.32) and @angular/cdk/@angular/material
(20.2.14) are already at the top of their v20 lines - so it does not pull in the
Angular 21 migration tracked by #1650.

Rebuilt frontend/ for the new framework code. backend/ is unchanged, as no
server/ source moved.

* Fill in PR number in release note (#1661)

* Bound remaining unbounded alias-resolution fan-outs in LND graph.ts and channels.ts   Fixes #1630 (#1651)

* Bound remaining unbounded alias-resolution fan-outs in LND graph.ts and channels.ts

Fixes #1630

* Address review feedback: fix options race, error handling, release notes

* Improve release notes entry to cover full PR scope

* Address review feedback: per-task options copy, exclude qs from alias requests

* Stop logging the eclair auth header at DEBUG level (#1664)

* Stop logging the eclair auth header at DEBUG level

getChannels in the eclair channels controller logged its whole request
options object. Eclair authenticates with HTTP basic auth, so those
options carry the configured lnApiPassword in an authorization header -
raising an eclair node's logLevel to DEBUG wrote
"authorization":"Basic <base64>" into the node log file, which is a
recoverable form of the credential and is routinely shared when
debugging.

The log now carries only the request url and form, matching every other
DEBUG log in the controllers. This was the only site in server/ passing a
whole options object to the logger; the rest log options.form, .url,
.body or .qs, none of which hold credentials.

Present since 0.12.0 and only reachable by opting in to DEBUG (the
default log level is ERROR), but it contradicted the logging guarantee
stated for #1659.

Found by scanning node logs at DEBUG while verifying the 0.15.10 branch
against the regtest fixture. Regression test added in
test/backend/eclair-channels.test.mjs; it fails on the previous code with
"auth header key must not reach the node log".

* Fill in PR number in release note (#1664)

---------

Co-authored-by: Osuji <weezdomosuji@gmail.com>
2026-08-03 22:49:14 -07:00
saubyk
f48a647272
Add CLAUDE.md with agent-facing notes on the codebase
Covers the things that are easy to get wrong and are not obvious from the
tree: that frontend/ and backend/ are committed build output that must be
regenerated rather than hand-edited, the parallel lnd/cln/eclair/shared
layout, the install and dev-server flags that differ from the defaults,
and the release-branch flow including how to recover a PR left open across
a release cut.

Process itself stays in CONTRIBUTING.md; this file points at it rather
than restating it.
2026-07-28 20:59:58 -07:00
saubyk
9cc86b2d4c Add rtl-docker-fixture Claude Code skill
Moves the docker/ regtest fixture instructions out of the always-loaded
CLAUDE.md into an on-demand skill, so they load only when someone is actually
working with the fixture.

Keeps the details docker/README.md does not cover: `docker compose up -d rtl`
silently restarts stopped dependencies (reconnecting a peer you stopped
mid-test), and the API handshake for verification scripts — base href /rtl,
CSRF token echoed as x-xsrf-token, SHA256-hashed password, and cln/getinfo
before any CLN channel endpoint.
2026-07-25 10:13:59 -07:00
saubyk
500bd31be5 Fill in PR number in release note (#1646) 2026-07-19 22:01:23 -07:00
saubyk
a4246c4fe6 Link the release notes folder from the README 2026-07-19 22:01:23 -07:00
saubyk
0a2c591177 Add release note for multi-node config auth-preservation fix (#1645) 2026-07-19 22:01:23 -07:00
Cosimo Ricciardi
a11179085b Add defensive guards for multi-node config updates 2026-07-19 22:01:23 -07:00
Cosimo Ricciardi
18a40ed183 Add defensive fallback for node map initialization 2026-07-19 22:01:23 -07:00
Cosimo Ricciardi
df52b9b77f Add defensive config handling for multi-node settings 2026-07-19 22:01:23 -07:00
Cosimo Ricciardi
bd0f515a6e Add defensive auth guards and cleanup iteration usage 2026-07-19 22:01:23 -07:00
Cosimo Ricciardi
40bd25d921 Address multi-node config auth preservation review 2026-07-19 22:01:23 -07:00
Cosimo Ricciardi
fa65568914 Prevent multi-node config overwrite during application settings updates 2026-07-19 22:01:23 -07:00
saubyk
fceb59bfed Remove deprecated outgoing_chan_id from QueryRoutes
The singular outgoing_chan_id query parameter on LND's QueryRoutes is
deprecated as of lnd 0.20.0 in favor of the plural outgoing_chan_ids.
The code path was unreachable in RTL anyway: no caller of the
GetQueryRoutes action ever populated outgoingChanId, so the query
parameter was never sent. Drop the unused field, the effect's
conditional URL builder, and the server-side passthrough.
2026-07-19 22:01:23 -07:00
saubyk
48b71d49e3 Address review: soften parity comment, guard async verify double-click
Two non-blocking review points on #1644:

- createHmacKey's comment claimed "exact parity" with otplib, but
  otplib's totpPadSecret under-repeats to 18 bytes for 1- and 9-byte
  secrets where this service pads to 20. Unreachable in RTL (secrets are
  always 10 bytes from generateSecret, field is read-only), and
  replicating the otplib bug has negative value - so the comment is
  corrected to state parity holds for the 10-byte secrets used here
  rather than universally.

- onVerifyToken's token check is now async, so two fast clicks on Verify
  could dispatch updateApplicationSettings twice (was synchronous
  before). Payload is idempotent so it was harmless, but guarded with an
  in-flight flag to restore the single-dispatch behavior.

Frontend/backend artifacts rebuilt; TOTP spec and lint pass.
2026-07-19 22:01:23 -07:00
saubyk
3082d9a1af Fill in PR number in release note (#1644) 2026-07-19 22:01:23 -07:00
saubyk
c5dc49711c Drop crypto-browserify polyfills by moving 2FA TOTP to WebCrypto
The frontend build pulled in crypto-browserify, stream-browserify and
vm-browserify (via tsconfig paths) only because otplib's
@otplib/plugin-crypto requires Node's crypto. That chain carried the
last production npm audit findings - the elliptic advisory
(GHSA-848j-6mx2-7j84, no fixed release) plus browserify-sign/create-ecdh
(issue #1634, item 3).

The two-factor-auth settings dialog is the only browser consumer of
otplib. It now uses a small WebCrypto TOTP service
(src/app/shared/services/totp.service.ts, RFC 6238: HMAC-SHA1, 6 digits,
30s step) instead, so otplib is no longer bundled and the three
polyfills plus their tsconfig path mappings are removed.

The backend still verifies login tokens with otplib, so the new service
must match it exactly - verified byte-for-byte against otplib and the
RFC 6238 test vectors (generateSecret/keyuri/generate/check parity).
Existing authenticator enrollments keep working. token check() is now
async (WebCrypto's digest is promise-based); the dialog's verify handler
was updated to match, and the value was never used for control flow.

Production npm audit now reports zero vulnerabilities (from 13, incl. 2
critical, at the start of this cleanup series). Verified on the docker
fixture: enrolled a 2FA secret from the new service, confirmed the
backend otplib accepts a token it produces at login, rejected
wrong/absent tokens. Unit spec covers RFC 6238 vectors, keyuri parity
and base32 round-trip; both API suites and the full frontend suite (204
specs) pass.
2026-07-19 22:01:23 -07:00
saubyk
4276a03463 Address review: document session-bound CSRF implications for API consumers 2026-07-19 22:01:23 -07:00
saubyk
030592ac23 Address review: fix logout -> re-login under session-bound CSRF tokens
Session-bound tokens broke re-login after logout: logoutUser destroys
the session, but the SPA navigated to the login page without a
document reload, so the surviving _csrf/XSRF-TOKEN cookies stayed
bound to the destroyed session id and the next login POST failed with
403 until a manual refresh. Hit both manual logout and the idle-timer
auto-logout.

Two coordinated fixes:

1. Frontend: the logout effect now performs a full document navigation
   to the login page (after the server logout completes, so the
   request is not aborted by the reload), which re-runs the handshake
   and mints a token bound to the fresh session. The logout reason
   previously travelled on the NgRx action stream, which cannot
   survive a reload - it is now handed over via sessionStorage (set
   after clearAll) and picked up and cleared by the login component.
   The SSO branch is unchanged (it already left the document).

2. Backend: the EBADCSRFTOKEN error path now re-mints the token for
   the current session before responding 403, so any client holding a
   stale token (e.g. after a server restart rotates the boot secret)
   self-heals on retry instead of looping on 403.

Verified on the fixture: reviewer's repro now shows login 200 ->
logout 200 -> stale-token login 403 (binding intact) with re-minted
cookies on the 403 -> retry 200; and the reload path (fresh GET /
after logout, what the full navigation does) logs in on the first
attempt. Both API suites, the CSRF battery, rtl.effects specs and the
full frontend suite pass; frontend and backend artifacts rebuilt.
2026-07-19 22:01:23 -07:00
saubyk
0af050a6b2 Fill in PR number in release note (#1643) 2026-07-19 22:01:23 -07:00
saubyk
e617fbb561 Replace deprecated csurf with csrf-csrf
csurf has been deprecated since 2022 and pins an old cookie release
with a known advisory; npm's only fix is a downgrade (issue #1634,
item 2). csrf-csrf v4 implements the same double-submit-cookie pattern
with an HMAC-signed, session-bound token keyed on the existing boot
secret (common.secret_key).

The frontend contract is unchanged: the token still arrives via the
XSRF-TOKEN cookie/header and is echoed as x-xsrf-token (all token
sources csurf accepted are still read), the signed cookie keeps the
_csrf name (now httpOnly, secure:false to match the session cookie on
plain-HTTP deployments), doubleCsrfProtection attaches req.csrfToken
so app.ts keeps working, and the error code is EBADCSRFTOKEN - already
handled in app.ts. The websocket upgrade check in authCheck.ts now
routes through the shared middleware; upgrade requests are GETs, so
its pass-through semantics are unchanged.

One fix this surfaced: app.ts called req.csrfToken() twice (cookie and
header). Under csurf every token validated against a stable secret;
under csrf-csrf each first-visit call mints a new token, desyncing the
XSRF-TOKEN cookie from the _csrf cookie it must equal. The token is
now generated once per request.

Tokens are session-bound, so a token stolen from one session no longer
validates in another - a check csurf's cookie mode did not perform.

Production npm audit drops from 6 low findings to 4, all in the
crypto-browserify/elliptic chain tracked in #1634.

Verified against the docker regtest fixture: both API suites (43
checks across LND, CLN and Eclair) plus a dedicated CSRF battery -
valid-token auth, missing token 403, garbage token 403, cross-session
replay 403, token stability across requests, the XSRF-TOKEN response
header for Quickpay, and the websocket handshake. Lint and build are
clean.
2026-07-19 22:01:23 -07:00
saubyk
6e61d1b759 Address review: coerce timeout_seconds to a positive finite number
The transport timeout added for the sendPayment race was derived from
req.body.timeout_seconds, which was only guarded by "|| 600": a
non-numeric value became NaN, which axios treats as no timeout,
silently dropping the transport ceiling for this endpoint.

timeout_seconds is now coerced to a positive finite number (falling
back to 600), which also normalizes the value sent to LND. Large
values are intentionally not capped: the transport bound must stay
above LND's own timeout_seconds bound or the race the margin fixes
would return.

Verified on the fixture: a payment sent with timeout_seconds "abc"
falls back to 600 and completes; the write suite re-passes.
2026-07-19 22:01:23 -07:00
saubyk
89b6313a5b Address review: avoid the sendPayment timeout race, keep paymentLookup bounded
sendPayment's timeout_seconds defaults to 600, equal to the wrapper's
600 s transport bound, so the transport timer (started first) would
win the race and surface ECONNABORTED instead of LND's clean
FAILURE_REASON_* result. The call now passes timeout_seconds plus a
60 s margin as the per-call transport timeout, so LND's mapped failure
always arrives first while the transport stays bounded for the actual
hang case (and a user-supplied timeout_seconds scales the bound with
it).

paymentLookup (/v2/router/track) deliberately keeps the 10-minute
default: it holds a browser-facing response open while tracking, and
payments in flight longer than that are delivered by the websocket
subscription path instead. Documented at the call site.

Verified on the fixture: a routed payment with an explicit
timeout_seconds succeeds; an unroutable payment returns LND's mapped
failure reason (Insufficient Balance - no ECONNABORTED, no transport
timeout message); paymentLookup returns the final state of a settled
payment. Both API suites re-pass.
2026-07-19 22:01:23 -07:00
saubyk
19aa332d61 Address review: protect the fire-and-forget channel close from the timeout
LND's DELETE /v1/channels/{channelPoint} streams until the closing tx
confirms, routinely longer than the wrapper's 10-minute bound. The
close call in closeChannel is fire-and-forget (202 returned
immediately, no .catch), so the timeout rejection would have become an
unhandled promise rejection and crashed the process ~10 minutes after
any close that had not yet confirmed. request-promise returned
Bluebird promises whose unhandled rejections only warned, which is why
this never crashed before.

The close now uses a copy of the options with timeout: 0 (same
treatment as the invoice/payment subscriptions) and a .catch that logs
through handleError - errors were never surfaced to the HTTP response
anyway, but logging beats Bluebird's silent warning. This was the only
call site without a rejection handler.

Verified on the fixture: opened a disposable 200k alice->bob channel
via RTL, closed it (202, gone from open and listed in closed after
mining), then requested a close for a bogus channel point - LND
rejects the stream, the catch logs the error (no auth headers in it),
and the process stays up. Read suite re-passes.
2026-07-19 22:01:23 -07:00
saubyk
5d1f55a9c6 Address review: exempt LND subscription streams from the request timeout
The 10-minute timeout added for review feedback would have aborted
LND's long-poll subscription streams (/v2/invoices/subscribe and
/v2/router/track), which legitimately stay open until an invoice
settles or a payment resolves - breaking real-time notifications for
any invoice paid more than 10 minutes after creation.

The wrapper now honors a per-call options.timeout (0 disables the
bound, axios semantics; the 10-minute default still applies everywhere
else), and both subscription calls pass timeout: 0. They also copy the
options object instead of mutating it: addInvoice hands the
session-cached options to subscribeToInvoice, so setting the timeout
in place would have leaked an unbounded timeout to every subsequent
request for that node (getOptions resets form/body/qs but not
timeout).

Verified on the regtest fixture: with a websocket client connected as
alice's frontend, creating an invoice opens the subscription stream,
it survives idle, and paying it from the CLN node delivers the SETTLED
event over the websocket in real time. The per-call override was also
verified directly (timeout: 1000 aborts a slow upstream with
ECONNABORTED; timeout: 0 waits it out). Both API suites (31 read + 12
write checks) re-pass.
2026-07-19 22:01:23 -07:00
saubyk
1efaa24d72 Address review: CSV-encode array form fields and bound request timeout
Review feedback on #1638 flagged two issues in the wrapper:

1. Array form values (eclair's ignoreNodeIds on findroutebetweennodes)
   encoded as "ignoreNodeIds=a,b" via String(), and worse, an empty
   array produced "ignoreNodeIds=" which Eclair's pubkey list parser
   rejects - breaking the default findroute path that worked under
   request-promise (qs omitted empty arrays). Arrays are now omitted
   when empty and comma-joined when not, matching Eclair's CsvSeq list
   format. Verified against the fixture: route eclair->bob->carol is
   found with an empty ignore list and disappears when bob is ignored.
   Under request-promise's qs indexed encoding (ignoreNodeIds[0]=...)
   Eclair never matched the field name, so the ignore list was silently
   dropped; this change makes it effective for the first time.

2. The shared transport had no request timeout, so a hung upstream
   held connections open indefinitely. Added a 10-minute bound,
   sized to the slowest legitimate operations (LND's /v2/router/send
   streams up to timeout_seconds=600; slow CLN channel operations get
   req.setTimeout(600000) upstream).

Both API suites (31 read + 12 write checks) re-pass on the fixture.
2026-07-19 22:01:23 -07:00
saubyk
9a2c702b4c Fill in PR number in release note (#1638) 2026-07-19 22:01:23 -07:00
saubyk
a8baba12bb Replace deprecated request/request-promise with axios
request has been deprecated since 2020 with an unfixed SSRF advisory and
pins vulnerable copies of form-data (critical), qs, tough-cookie and
uuid - 8 of the 13 remaining production audit findings, none fixable by
version bumps (issue #1634, item 1).

All 36 backend files that imported request-promise now use a small
compatibility wrapper (server/utils/request.ts) backed by axios, which
is already a production dependency. The wrapper accepts the existing
options shape (qs, form - object or pre-encoded string, body,
baseUrl/uri, rejectUnauthorized, json), resolves with the response body
directly, and rejects with a plain object mirroring request-promise's
StatusCodeError/RequestError shape, so CommonService.handleError works
unchanged (ECONNREFUSED -> 503, Eclair StatusCodeError -> 500, nested
error body extraction). Auth headers are excluded from rejected errors
so they cannot leak into logs. Callers without json: true (block
explorer, currency rates) still get raw text bodies, and LND's
line-delimited /v2/router/send stream still surfaces as a string for
the existing parser.

Only behavioral code change: CLN verifyMessage used request-promise's
callback style and was ported to the same promise style as signMessage;
four Eclair handlers gained explicit returns to satisfy
noImplicitReturns once the import became typed.

Production npm audit drops from 13 findings (2 critical) to 6 low, all
in the crypto-browserify/elliptic chain tracked in #1634.

Verified against the docker regtest fixture with 43 API checks across
LND, Core Lightning and Eclair: reads, invoice creation, a routed LND
payment over the streaming endpoint, cross-implementation payments from
CLN and Eclair, message sign/verify, channel backup to disk, and
bad-invoice/node-unreachable error mapping. Lint and both production
builds are clean.
2026-07-19 22:01:23 -07:00
saubyk
6e48241d85 Migrate sat_per_byte to sat_per_vbyte for LND requests
Per LND v0.21.0 release notes, the sat_per_byte option will be removed
in v0.22 across CloseChannel, OpenChannel, SendCoins, SendMany, and
walletrpc.BumpFee. LND already treats sat_per_byte as sat/vbyte
internally, so this is a pure rename with no value conversion. Updates
both the wire-format strings sent to LND and the matching TypeScript
identifiers across the close-channel, open-channel, send-coins, and
bump-fee paths.
2026-07-19 22:01:23 -07:00
saubyk
890db72ab6 Restore the Enhancements section header in the release notes 2026-07-19 22:01:23 -07:00
saubyk
95f064ae31 Fill in PR number in release note (#1637) 2026-07-19 22:01:23 -07:00
saubyk
bb2a228662 Realign the Reports Scroll Range select with the date picker
The a11y fix in #1609 wrapped the bare Scroll Range mat-select in a
mat-form-field for its label, but the wrapper reserved subscript space
(78.8px vs the date field 56px) and anchored to the row top, leaving
the date picker ~11px lower on every implementation reports screen.
Use subscriptSizing="dynamic" (no hints are used) and center on the
cross axis, restoring the aligned 56px row from v0.15.8 while keeping
the label. Verified headlessly against the regtest fixture: both
fields now render at identical top/height.

Fixes #1635
2026-07-19 22:01:23 -07:00
saubyk
b47e32c88c Bump pdfmake to 0.3.11 to fix its SSRF advisory
The fix is within the pinned 0.3.x line but the exact pin kept npm
update from reaching it. Clears the last high-severity production
vulnerability; frontend build and full spec suite verified.
2026-07-19 22:01:23 -07:00
saubyk
f75ec24844 Fill in PR number in release note (#1633) 2026-07-19 22:01:23 -07:00
saubyk
09494dcfc0 Update project dependencies to resolve Dependabot security alerts
Apply the bumps from all 20 open Dependabot security PRs (#1583-#1617)
in one pass on the release branch: axios 1.16.0, ws 8.21.0, the
socket.io server stack, express path-to-regexp, follow-redirects,
lodash and the remaining flagged transitive deps. Angular framework
packages move in lockstep to 20.3.26 and the CLI/build toolchain to
20.3.32, which drops the vulnerable node-forge from the tree entirely.
Also pick up in-range fixes without open PRs (qs, uuid, tough-cookie,
cookie, ajv, bn.js, elliptic, socket.io-parser).

npm audit: 85 vulnerabilities (23 prod) -> 30 (14 prod). The remainder
(request/request-promise, csurf, pdfmake, crypto-browserify chain)
needs code changes, not bumps, and is tracked separately.

Verified: lint, 199 frontend specs, backend + frontend production
builds, and an end-to-end smoke test against the docker regtest
fixture (LND, CLN and Eclair auth/getinfo/channels + WS upgrade).
2026-07-19 22:01:23 -07:00
saubyk
da74a84e7e Fill in PR number in release note (#1636) 2026-07-19 22:01:23 -07:00
saubyk
c1a46b1cbd Document the Dependabot dependency-update process in CONTRIBUTING.md
Dependabot PRs target master and are resolved in batch PRs against the
release branch, but the process was undocumented. Add a "Handling
Dependabot PRs" section covering target collection, pinned in-range
fixes, Angular lockstep, from-scratch lockfile regeneration, artifact
rebuild, verification, and issue-tracking for deprecated packages.
2026-07-19 22:01:23 -07:00
saubyk
9a799ea314 Add a topology diagram to the docker fixture README
Mermaid flowchart (rendered by GitHub) showing the channel graph, each
node's chain-backend link -- including eclair's dedicated wallet and
hashblock ZMQ endpoint -- and the protocol RTL uses to reach each node.
2026-07-19 22:01:23 -07:00
saubyk
54359f2ceb Fill in PR number in release note (#1632) 2026-07-19 22:01:23 -07:00
saubyk
6e55059fe2 Add an Eclair node to the regtest docker fixture
Completes backend coverage of RTL's three implementations in the docker/
dev fixture: an eclair node (polarlightning/eclair 0.13.1) joins the three
LND nodes and the CLN node, wired to RTL over its HTTP API with basic auth,
and the seed opens an eclair->bob channel (3.5M sats, 1M pushed), sends two
direct payments and leaves one open invoice.

Non-obvious plumbing this needed:

- polarlightning/eclair instead of acinq/eclair: the official image is
  amd64-only (useless on Apple Silicon) and its newest versioned tag is
  years stale; Polar builds the same ACINQ source multi-arch.
- Eclair has no on-chain wallet of its own -- it drives a bitcoind wallet.
  A new eclair-wallet-init container creates a dedicated "eclair" wallet
  before the node starts; without it eclair attaches to "the default
  loaded wallet", i.e. the rtldev mining wallet.
- bitcoind now also publishes a zmqpubhashblock endpoint (28336): eclair's
  bitcoind.zmqblock consumes the hashblock topic, not the rawblock one LND
  uses. Wired to rawblock, eclair never sees new blocks and channels hang
  in WAIT_FOR_FUNDING_CONFIRMED.
- Eclair confirms channels at 8 blocks (channel.min-depth-blocks), not 6,
  and 'open' returns before the funding tx is broadcast -- the seed waits
  for the mempool and mines 8 blocks for this channel.

Adds a bin/e-cli helper (eclair-cli with the API password), updates the
README, and verified end-to-end: seed completes, the channel reaches
NORMAL, both payments settle, and RTL's /rtl/api/ecl endpoints return the
node, channel and invoice data.
2026-07-19 22:01:23 -07:00
saubyk
c2b8670099 Rebuild compiled cln/channels.js to match its source (#1606)
The #1606 fix added 'channel.connected = !!channel.peer_connected' to
server/controllers/cln/channels.ts but the committed compiled artifact
backend/controllers/cln/channels.js was never regenerated, leaving it stale.
Rebuild it so the committed backend output matches its TypeScript source.
2026-07-19 22:01:23 -07:00
saubyk
e0fce065d5 Address 2nd review: guard limiter callbacks, CLN postPeer aliases, one-shot done
Follow-up to the second #1629 review:

- F4: the limiter invokes its done callback outside the surrounding .then/.catch,
  so a throw in the response-send body became an unhandled rejection with no
  response (a 500 -> hang regression, notably on LND postPeer where the inner
  .catch was removed). Wrap each converted done body in try/catch that sends the
  error response, guarded by res.headersSent.
- F5: CLN postPeer re-listed peers but never resolved their aliases, so a freshly
  connected CLN peer came back with a raw node id (the frontend uses this response
  directly). Resolve aliases through the same bounded limiter, matching LND postPeer.
- F6: make runWithConcurrencyLimit fire 'done' exactly once via a one-shot guard,
  so multiple synchronous completions (e.g. non-function task elements) can't
  double-send the response.
2026-07-19 22:01:23 -07:00
saubyk
e11899a051 Broaden release note to cover LND peers parity and getAlias hardening (#1629) 2026-07-19 22:01:23 -07:00
saubyk
bd74132265 Address review: self-contained CLN getAlias, LND peers bound, limiter guard
Follow-up to the #1501 review (PR #1629):

- F1: CLN getAlias now builds its request from selNode.authentication.options
  instead of the shared module-level 'options'. That coupling meant a cold
  Peers/route lookup dereferenced a null 'options'; with the new limiter
  swallowing per-task throws, that returned 200 with every alias unset. Aliases
  now resolve regardless of call order, with a truncated-id fallback if auth
  options are somehow absent.
- F2: mirror the 20-way concurrency bound to LND peers (getPeers and postPeer),
  which had the same unbounded Promise.all alias fan-out. Eclair resolves
  aliases inline from a bulk nodes list, so it needs no change.
- F3: normalize runWithConcurrencyLimit's start count to at least 1 so a
  non-positive limit can't leave 'done' unfired and hang the response.
2026-07-19 22:01:23 -07:00
saubyk
a09eb7d4c5 Fill in PR number in release note (#1629) 2026-07-19 22:01:23 -07:00
saubyk
fbd336a89b Bound CLN alias resolution on peers and route lookups (#1501)
RTL resolves peer aliases by calling listnodes once per peer. A prior fix
(1cec7b1) bounded this to 20 concurrent calls plus a cache for the channel
list, but the peers list and route lookup still used an unbounded Promise.all,
firing one request per peer at once. On nodes with many peers this overwhelms
clnrest and fails with 'Resource temporarily unavailable (os error 11)'
(EAGAIN), so aliases fall back to raw node IDs.

- peers.ts and network.ts getRoute now resolve aliases via
  runWithConcurrencyLimit(tasks, 20, ...), matching the channel list.
- Harden runWithConcurrencyLimit to call done() immediately for an empty task
  list; otherwise an empty peers/route set would never send a response.
- Give the alias cache a 6h TTL and a max size (evicting oldest) so aliases
  refresh without an RTL restart and the cache can't grow unbounded.
2026-07-19 22:01:23 -07:00
saubyk
75dba90fae Add 0.15.9 release note for the accessibility form-label fix (#1609) 2026-07-19 22:01:23 -07:00
saubyk
f93bc7b1d8 Restore trailing newlines stripped from six modal templates
The accessibility edits dropped the final newline from six form templates.
Add it back so these files end with a newline again (POSIX text-file
convention; keeps diffs clean and avoids no-newline lint noise).
2026-07-19 22:01:23 -07:00
SIDHARTH20K4
86d10df369 fix: capitalize Info Type label for consistency 2026-07-19 22:01:23 -07:00
SIDHARTH20K4
eed6b8aca2 fix: address review feedback - remove remaining positive tabindex values and add CLN parity fixes 2026-07-19 22:01:23 -07:00
SIDHARTH20K4
522b7e307d fix: address review feedback - fix invalid button types and remove fxFlex from mat-select 2026-07-19 22:01:23 -07:00