Skip to content

firewall+faraday: merge ForwardingAbility feature branch#1328

Open
bitromortac wants to merge 12 commits into
masterfrom
faraday-forwarding-ability
Open

firewall+faraday: merge ForwardingAbility feature branch#1328
bitromortac wants to merge 12 commits into
masterfrom
faraday-forwarding-ability

Conversation

@bitromortac

Copy link
Copy Markdown
Contributor

This merges a feature branch where we add support for faraday's new ForwardingAbility endpoint.

The merge conflicts will be resolved by a rebase on master in a later push.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates the Faraday ForwardingAbility feature into the Lightning Terminal (LiT) ecosystem. It significantly enhances the privacy architecture by implementing a gRPC interceptor that manages privacy mapping for non-LND sub-daemons, ensuring that sensitive identifiers are obfuscated before reaching external services. The changes include comprehensive updates to the configuration, documentation, and test suites to support these new privacy-preserving capabilities.

Highlights

  • Faraday Integration: Enabled the Faraday ForwardingAbility endpoint and implemented peer pubkey obfuscation within the firewall's privacy mapper.
  • Privacy Mapping Architecture: Introduced a new gRPC interceptor for LNC sessions to apply privacy mapping to non-LND sub-daemon requests, ensuring consistent privacy protection.
  • Configuration Updates: Added a noprivacy flag for autopilot sessions and introduced PrivacyTimestampVariation to the configuration to support flexible timestamp obfuscation.
  • Dependency Management: Updated project dependencies and configuration structures to align with the new privacy mapping requirements.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces gRPC unary and stream interceptors to apply privacy mapping for non-LND sub-daemon requests (such as Faraday) within LNC sessions, and enables peer pubkey obfuscation for Faraday's ForwardingAbility endpoint. It also adds a hidden noprivacy flag to autopilot sessions, refactors the Faraday subserver, and updates various dependencies. Feedback on these changes includes: ensuring the default timeVariation is applied when zero as documented; validating PrivacyTimestampVariation in the development config to prevent negative durations and potential integer overflows; optimizing the checkers map allocation in the privacy mapper to reduce overhead; and updating the go.mod replace directives to point to official upstream repositories instead of a personal fork.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 95 to 101
return &PrivacyMapper{
db: newDB,
randIntn: randIntn,
sessionDB: sessionDB,
db: newDB,
randIntn: randIntn,
sessionDB: sessionDB,
timeVariation: timeVariation,
permsMgr: permsMgr,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The documentation for NewPrivacyMapper states that if timeVariation is zero, DefaultTimeVariation is used. However, the implementation does not apply this default value, leaving timeVariation as 0 if passed as such. This can disable timestamp obfuscation entirely when a zero value is provided.

Suggested change
return &PrivacyMapper{
db: newDB,
randIntn: randIntn,
sessionDB: sessionDB,
db: newDB,
randIntn: randIntn,
sessionDB: sessionDB,
timeVariation: timeVariation,
permsMgr: permsMgr,
}
if timeVariation == 0 {
timeVariation = DefaultTimeVariation
}
return &PrivacyMapper{
db: newDB,
randIntn: randIntn,
sessionDB: sessionDB,
timeVariation: timeVariation,
permsMgr: permsMgr,
}

Comment thread config_dev.go Outdated
Comment on lines +70 to +72
if c.PrivacyTimestampVariation != 0 {
cfg.PrivacyTimestampVariation = c.PrivacyTimestampVariation
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The PrivacyTimestampVariation override from the development configuration is applied directly without validation. If a negative duration is supplied, casting it to uint64 in the privacy mapper (e.g., uint64(p.timeVariation)) will cause an integer overflow, leading to extremely large intervals and incorrect obfuscation behavior. Consider validating that the duration is non-negative.

	if c.PrivacyTimestampVariation != 0 {
		if c.PrivacyTimestampVariation < 0 {
			return fmt.Errorf("privacy-timestamp-variation cannot be negative")
		}
		cfg.PrivacyTimestampVariation = c.PrivacyTimestampVariation
	}

Comment on lines 536 to +545
flags session.PrivacyFlags) map[string]mid.RoundTripChecker {

return map[string]mid.RoundTripChecker{
//nolint:ll
"/frdrpc.FaradayServer/ForwardingAbility": mid.NewResponseRewriter(
&frdrpc.ForwardingAbilityRequest{},
&frdrpc.ForwardingAbilityResponse{},
handleForwardingAbilityResponse(db, flags),
mid.PassThroughErrorHandler,
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The checkers method allocates a new map and instantiates all round-trip checkers (along with their request/response templates and handler closures) on every single request. This introduces unnecessary allocation overhead and garbage collection pressure. Consider refactoring this lookup to use a switch-case or a lazy-initialization helper that only instantiates the specific checker requested by the URI.

Comment thread go.mod Outdated
Comment on lines +263 to +265
replace github.com/lightninglabs/faraday => github.com/bitromortac/faraday v0.0.0-20260611104839-edc3a405e6ec

replace github.com/lightninglabs/faraday/frdrpc => github.com/bitromortac/faraday/frdrpc v0.0.0-20260611104839-edc3a405e6ec

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The replace directives point to a personal fork (github.com/bitromortac/faraday). While useful during development, merging code to the main branch with dependencies pointing to personal forks can lead to build fragility and security risks if the fork is deleted or modified. Please ensure these are updated to point to the official upstream repository before merging.

@bitromortac
bitromortac force-pushed the faraday-forwarding-ability branch from c9df71e to 26b3b10 Compare June 12, 2026 13:30
@bitromortac

bitromortac commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on master, the changes can be seen with

git range-diff master c9df71e HEAD.

The changes are basically in the config, the release notes, and dropping some faraday mod update. This has the latest faraday version of lightninglabs/faraday#244, but we may still wait for faraday adding db cleanup routines before we merge this, which will require another version change.

@bitromortac
bitromortac requested a review from ViktorT-11 June 12, 2026 13:33
@bitromortac bitromortac added the no-changelog This PR is does not require a release notes entry label Jun 12, 2026

@ViktorT-11 ViktorT-11 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, let's get these changes into master 🔥! As discussed offline though, let's ship this in the next minor release though, instead of the next major litd release?

@bitromortac
bitromortac force-pushed the faraday-forwarding-ability branch from 26b3b10 to e20dbdb Compare June 23, 2026 08:42
@bitromortac

Copy link
Copy Markdown
Contributor Author

Rebased on master, added a temp replace for lightninglabs/faraday#245, which will be removed, once merged.

In this commit we make faraday a first class subserver instead of only
incorporating its grpc subserver. The bitcoind config is already part of
the faraday config.
This can be useful for testing.
This is useful to test non-obfuscated sessions.
The checkAndReplaceIncomingRequest and replaceOutgoingResponse helpers
each looked up the session from sessionDB by ID, resulting in two
redundant GetSession round-trips per intercepted request. Move the
lookup to the top of Intercept and pass the resolved *session.Session
into both helpers so the session is fetched exactly once.

This also makes the helpers reusable from callers that already have the
session in hand, such as the unary interceptor introduced in the next
commit.
The privacy mapper currently runs only inside LND's middleware chain
via PrivacyMapper.Intercept, so requests that LNC routes directly to
non-LND sub-daemons (e.g. Faraday) reach the sub-daemon with real
channel IDs, peer pubkeys and amounts. Add a gRPC unary server
interceptor on the LNC session server that applies the same
pseudo-to-real request mapping and real-to-pseudo response mapping for
these calls. LND URIs are skipped because LND's middleware already
covers them.

The interceptor is fail-close: it blocks the request if any dependency
(permissions manager, session DB, privacy DB) is not yet initialized,
if the call does not carry a session ID, or if no privacy checker is
registered for the URI. A small PermissionsManager interface is
introduced so the mapper can identify LND URIs without a hard
dependency on the perms package.
The unary interceptor added in the previous commit leaves streaming RPCs
unmapped, so a privacy-enabled LNC session can still open a stream
against a non-LND sub-daemon (e.g. Faraday) and receive real channel
IDs, peer pubkeys and amounts.

Add the streaming counterpart with the same fail-close logic: LND URIs
and sessions without privacy pass through; non-LND streams from
privacy-enabled sessions are rejected with PermissionDenied until
per-message stream rewriting is implemented.
Documents the dual-path privacy mapping architecture: LND requests are
mapped via LND's middleware chain (PrivacyMapper.Intercept) after being
proxied to LND, while non-LND sub-daemon requests are mapped at the LNC
gRPC interceptor (PrivacyMapper.UnaryInterceptor) before reaching the
sub-daemon. Each flow is illustrated with a mermaid sequence diagram.
Pubkeys in the Peers field are obfuscated. Other data is averaged over
large timespans usually, so that doesn't lead to privacy leaks.
@bitromortac
bitromortac force-pushed the faraday-forwarding-ability branch from e20dbdb to 042baef Compare June 25, 2026 13:05
@bitromortac

Copy link
Copy Markdown
Contributor Author

Updated to latest faraday.

@lightninglabs-deploy

Copy link
Copy Markdown

@bitromortac, remember to re-request review from reviewers when ready

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR is does not require a release notes entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants