Commit graph

1321 commits

Author SHA1 Message Date
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
SIDHARTH20K4
5690367d07 fix: add missing mat-label to form fields and remove positive tabindex values 2026-07-19 22:01:23 -07:00
saubyk
46c710ca7a Backfill 0.15.9 release notes for pre-process merged PRs
Several PRs were merged onto Release-0.15.9 before the per-PR release-notes
process was established, leaving them undocumented. Add entries for:

- #1581 Fix page-load error when a channel alias is undefined (Bug Fixes)
- #1601 Fix stale auth options blocking a not-yet-ready node (Bug Fixes)
- #1582 Add Disable Authentication option (Enhancements)
- #1621 Rebuild the regtest docker fixture (Developer Tooling)
2026-07-19 22:01:23 -07:00
saubyk
1782ae2b20 Fill in PR number in release note (#1627) 2026-07-19 22:01:23 -07:00
saubyk
343338cd4b Show Blocks till Maturity by default on LND Pending Force Closing list (#1567)
Blocks-till-maturity is critical information for a force-closing channel but
was only visible in the per-channel detail modal. The column and its data
binding already existed in the pending force-closing table (and was selectable
via column settings); it was just missing from the default column selection.
Add blocks_til_maturity to the pending_force_closing default columnSelection
and columnSelectionSM so it is surfaced on the list by default on both desktop
and mobile.
2026-07-19 22:01:23 -07:00
saubyk
30712392e6 Fill in PR number in release note (#1626) 2026-07-19 22:01:23 -07:00
saubyk
2a9aee2597 Restore items-per-page dropdown on paginated tables (#1580)
A dependency-update commit in the 0.15.8-beta cycle mechanically renamed
the paginator binding [showFirstLastButtons] to [hidePageSize] on every
mat-paginator while keeping the same 'screenSize === XS ? false : true'
expression. The two properties have opposite polarity, so this inverted
the behavior: on desktop the page-size selector was hidden (locking users
to 10 items per page) and the first/last-page buttons were dropped as
collateral. Revert the ~44 affected paginators back to [showFirstLastButtons]
across the LND, CLN, Eclair and shared tables.
2026-07-19 22:01:23 -07:00
saubyk
f518488ecb Clarify connected-mirror comment and pin the fixture rune path
Address review F7/F8 on #1625:

F7 (verification): the onchain.ts `connected === false` branch reads /v1/listfunds
(CLN's own connected field) and only buckets balance as inactive — it is not the
listPeerChannels mirror and does no close logic, so the coercion activates nothing
there. Reword the mirror comment, which inaccurately implied onchain.ts consumes it;
the mirror simply keeps the documented backward-compat `connected` field defined.

F8: hardcode the rune path in create-rune.sh to /root/.lightning/rtl.rune so it
matches the volume mount, healthcheck and RTL runePath instead of deriving it from
${LIGHTNINGD_DATA}, removing the silent-divergence risk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
cbf7a14c95 Guard the LND channel information modal explorer link (#1606 parity)
Address review F6 on #1625: the LND channel information modal has the same
unguarded selNode.settings.blockExplorerUrl binding as the CLN one, and it is
opened without selNode from the active-HTLCs and channel-backup tables, so it can
blank out the same way. Guard the explorer link (*ngIf + a no-op click when the
url is absent) so a missing selNode can no longer blank the dialog. Eclair's modal
doesn't use selNode.settings, so it needs no change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
9c3cd983b4 Make the CLN dev-fixture rune creation self-healing
Address review F5 on #1625: create-rune.sh was a one-shot poststart script — if
the RPC wasn't ready within its poll or createrune failed, it exited without ever
writing rtl.rune, and since the cln healthcheck gates on that file and rtl waits
on service_healthy, a failed pass deadlocked the whole stack until 'down -v'.

Drive rune creation from the healthcheck instead: the script is now a quick,
idempotent single attempt, and the healthcheck runs it on every interval, so a
transient RPC-startup race just retries and self-heals. Moved the script out of
lightning-poststart.d to /opt and updated the healthcheck, compose comment and
README accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
99cb60d2a7 Type selNode as the RTL Node model in the pending table
Address review F4 on #1625: the new selNode field resolved to the global DOM
Node type because the RTL Node model was not imported. Import Node from
shared/models/RTLconfig so the field, the rootSelectedNode store value, and the
CLNChannelInformationComponent it feeds all agree, restoring type-checking.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
c15fa04986 Fix CLN channel View Info modal blanking for disconnected channels (#1606)
The channel information modal renders a block-explorer link from
selNode.settings.blockExplorerUrl, but the pending/inactive channels table
opened the modal without passing selNode. With it undefined, that binding threw
during change detection and blanked every field below it — State, Connected,
Private and the balances all rendered without a value. A disconnected channel
moves to the pending/inactive table, so this is what surfaced on View Info for a
disconnected channel (the symptom in the original report).

Pass selNode from the pending table (matching the open table), and guard the
modal's explorer link (*ngIf + a no-op click when the url is absent) so a missing
selNode can no longer blank the whole dialog. Add a regression test asserting the
pending table passes selNode when opening the modal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
b790dc7abf Add a Core Lightning node to the regtest docker fixture
The fixture had only bitcoind + three LND nodes, so RTL's Core Lightning screens
had no backend to exercise. Add a `cln` node (official elementsproject/lightningd
image, multi-arch) wired to RTL over clnrest with rune auth, and have the seed
open a cln->alice channel so the CLN channel/peer screens have real data.

- docker-compose.yml: cln service (clnrest on 0.0.0.0:3010, https), a healthcheck
  gated on the rune file so rtl waits for it, and rtl now mounts the cln volume
  read-only and depends on cln being healthy. The rtl image is parameterized via
  ${RTL_IMAGE:-...} so an unreleased build can be tested against the fixture.
- cln/poststart.d/create-rune.sh: once the RPC is up, create a master rune and
  write it as LIGHTNING_RUNE="..." where RTL reads it (runePath). Polls for RPC
  readiness because the image entrypoint can invoke poststart before the socket
  exists.
- RTL-Config.regtest.json: add node index 4 (CLN, rune auth, https://cln:3010).
- seed.sh: fund cln, connect to alice, open a 4,000,000 sat channel, wait active.
- README + release notes updated.

Used to verify the CLN channel connection-status fix (#1606) end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
80af65d7fe Read peer_connected in pending-table close-channel guard
Address review F3 on #1625: the Close-Channel *ngIf still read the legacy
`connected` field while its neighboring column now reads peer_connected. Point
it at peer_connected directly so it no longer depends on the backend mirror,
removing the latent coupling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
512aea96e5 Coerce mirrored peer_connected to a boolean
Address review feedback on #1625: copy peer_connected onto the legacy
`connected` field as a real boolean (!!), so strict-equality readers such as
onchain.ts's `connected === false` behave correctly when peer_connected is
absent, instead of leaving `connected` undefined.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
5659ba250b Add release notes doc for 0.15.9
Introduce a release-notes/ folder to collect the changes for each release, and
add Release-notes-0.15.9.md with the entry for the CLN channel connection status
fix (#1606 / #1625). New process: every PR for a release appends its entry to the
respective release notes document.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
saubyk
16d48417d8 Fix CLN channel connection status shown inconsistently (#1606)
CLN's listpeerchannels reports connection state as peer_connected, but the
open/pending channel list columns read the legacy `connected` field, which the
backend never populated. It was therefore always empty, so the list always
rendered "Disconnected" while the detail panel (which reads peer_connected)
showed the true state — the contradiction reported in #1606.

Normalize `connected = peer_connected` in the backend listPeerChannels response
so legacy consumers stay in sync, and point the list columns at peer_connected
directly. Add regression specs asserting the connected column follows
peer_connected even when the legacy field disagrees.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 22:01:23 -07:00
Matt Hill
42cb3c76e8 Fix setOptions cache poisoning when one node's auth load fails 2026-07-19 22:01:23 -07:00
ShahanaFarooqui
266167cf53 Update documentation for Disable Authentication 2026-07-19 22:01:23 -07:00
ShahanaFarooqui
0057bee53d Add Disable Authentication option in the frontend 2026-07-19 22:01:23 -07:00
ShahanaFarooqui
4613b889bf Add Disable Authentication option in the backend 2026-07-19 22:01:23 -07:00
ShahanaFarooqui
7d32bd68e9 Fix error on page load if channels alias is undefined 2026-07-19 22:01:23 -07:00
ShahanaFarooqui
7d676dc940 Update version 0.15.9 2026-07-19 22:01:23 -07:00
Suheb
3ae6d65ca2
Update rtlreviewbot.yml
Updated the timeout limit to 20 minutes
2026-07-19 13:35:34 -07:00
saubyk
1a6cb0b0a8 Source .env in seed.sh so it prints the real password
Docker Compose reads .env automatically; bash does not. seed.sh referenced
${RTL_PASSWORD:-password} without sourcing it, so the default always won and
the summary told the user to log in with 'password' -- the blacklisted value
this branch just removed.
2026-07-16 00:15:20 -07:00
saubyk
df48de1140 Fix the regtest fixture using a password RTL blacklists
The fixture added in #1621 set multiPass to "password". RTL blacklists weak
passwords (PASSWORD_BLACKLIST in consts-enums-functions.ts: 'password',
'changeme', 'moneyprintergobrrr') and forces a change when one is used:
login.component.ts sets defaultPassword: true, and app.component.ts then
redirects to /rtl/settings/auth.

So every login with the documented password was bounced to the change
password screen and never reached the dashboard. The check is session based
rather than first run only, so this happened on every fresh browser session,
not just the first.

Password is now 'rtldev'. .env documents why it must stay off the blacklist.
2026-07-16 00:02:00 -07:00