From 57879346fc1af10111b687ba3cde23c887417874 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Sun, 20 Apr 2025 10:55:34 +0200 Subject: [PATCH 1/3] session: add session ID to grpc metadata via context --- session/context.go | 36 ++++++++++++++++++++++++++ session/server.go | 5 ++-- session_rpcserver.go | 60 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 session/context.go diff --git a/session/context.go b/session/context.go new file mode 100644 index 000000000..0839835c1 --- /dev/null +++ b/session/context.go @@ -0,0 +1,36 @@ +package session + +import ( + "encoding/hex" + + "google.golang.org/grpc/metadata" +) + +type contextKey struct { + name string +} + +var sessionIDCtxKey = contextKey{"lit_session_id"} + +func FromGrpcMD(md metadata.MD) (ID, bool, error) { + val := md.Get(sessionIDCtxKey.name) + if len(val) == 0 { + return ID{}, false, nil + } + + b, err := hex.DecodeString(val[0]) + if err != nil { + return ID{}, false, err + } + + sessID, err := IDFromBytes(b) + if err != nil { + return ID{}, false, err + } + + return sessID, true, nil +} + +func AddToGrpcMD(md metadata.MD, id ID) { + md.Set(sessionIDCtxKey.name, hex.EncodeToString(id[:])) +} diff --git a/session/server.go b/session/server.go index 75c0e3edf..8dd75b44f 100644 --- a/session/server.go +++ b/session/server.go @@ -18,7 +18,8 @@ import ( type sessionID [33]byte -type GRPCServerCreator func(opts ...grpc.ServerOption) *grpc.Server +type GRPCServerCreator func(sessionID ID, + opts ...grpc.ServerOption) *grpc.Server type mailboxSession struct { server *grpc.Server @@ -70,7 +71,7 @@ func (m *mailboxSession) start(session *Session, } noiseConn := mailbox.NewNoiseGrpcConn(keys) - m.server = serverCreator(grpc.Creds(noiseConn)) + m.server = serverCreator(session.ID, grpc.Creds(noiseConn)) m.wg.Add(1) go m.run(mailboxServer) diff --git a/session_rpcserver.go b/session_rpcserver.go index b20700948..96c255a47 100644 --- a/session_rpcserver.go +++ b/session_rpcserver.go @@ -26,6 +26,7 @@ import ( "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/macaroons" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "gopkg.in/macaroon-bakery.v2/bakery" "gopkg.in/macaroon-bakery.v2/bakery/checkers" "gopkg.in/macaroon.v2" @@ -77,10 +78,24 @@ func newSessionRPCServer(cfg *sessionRpcServerConfig) (*sessionRpcServer, // actual mailbox server that spins up the Terminal Connect server // interface. server := session.NewServer( - func(opts ...grpc.ServerOption) *grpc.Server { - allOpts := append(cfg.grpcOptions, opts...) + func(id session.ID, opts ...grpc.ServerOption) *grpc.Server { + allOpts := []grpc.ServerOption{ + grpc.StreamInterceptor( + addSessionIDToStreamCtx(id), + ), + grpc.ChainUnaryInterceptor( + addSessionIDToUnaryCtx(id), + ), + } + + allOpts = append(allOpts, cfg.grpcOptions...) + allOpts = append(allOpts, opts...) + + // Construct the gRPC server with the options. grpcServer := grpc.NewServer(allOpts...) + // Register various grpc servers with the LNC session + // server. cfg.registerGrpcServers(grpcServer) return grpcServer @@ -94,6 +109,47 @@ func newSessionRPCServer(cfg *sessionRpcServerConfig) (*sessionRpcServer, }, nil } +type wrappedServerStream struct { + grpc.ServerStream + ctx context.Context +} + +func (w *wrappedServerStream) Context() context.Context { + return w.ctx +} + +func addSessionIDToStreamCtx(id session.ID) grpc.StreamServerInterceptor { + return func(srv interface{}, ss grpc.ServerStream, + info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + + md, _ := metadata.FromIncomingContext(ss.Context()) + mdCopy := md.Copy() + session.AddToGrpcMD(mdCopy, id) + + // Wrap the original stream with our custom context. + wrapped := &wrappedServerStream{ + ServerStream: ss, + ctx: metadata.NewIncomingContext( + ss.Context(), mdCopy, + ), + } + + return handler(srv, wrapped) + } +} + +func addSessionIDToUnaryCtx(id session.ID) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler) (resp any, err error) { + + md, _ := metadata.FromIncomingContext(ctx) + mdCopy := md.Copy() + session.AddToGrpcMD(mdCopy, id) + + return handler(metadata.NewIncomingContext(ctx, mdCopy), req) + } +} + // start all the components necessary for the sessionRpcServer to start serving // requests. This includes resuming all non-revoked sessions. func (s *sessionRpcServer) start(ctx context.Context) error { From e57e11865c7ccbfd193fd5c970fe0710f7f3ca38 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Sun, 20 Apr 2025 10:56:32 +0200 Subject: [PATCH 2/3] go.mod: update LND and lndclient deps --- go.mod | 14 +++++++++----- go.sum | 28 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 100d0c8f0..fc08ab23b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.5 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 - github.com/btcsuite/btcwallet/walletdb v1.4.4 + github.com/btcsuite/btcwallet/walletdb v1.5.1 github.com/davecgh/go-spew v1.1.1 github.com/go-errors/errors v1.0.1 github.com/golang-migrate/migrate/v4 v4.17.0 @@ -34,7 +34,7 @@ require ( github.com/lightningnetwork/lnd/clock v1.1.1 github.com/lightningnetwork/lnd/fn v1.2.3 github.com/lightningnetwork/lnd/fn/v2 v2.0.8 - github.com/lightningnetwork/lnd/kvdb v1.4.13 + github.com/lightningnetwork/lnd/kvdb v1.4.15 github.com/lightningnetwork/lnd/tlv v1.3.0 github.com/lightningnetwork/lnd/tor v1.1.6 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f @@ -68,11 +68,11 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcutil/psbt v1.1.10 // indirect github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c // indirect - github.com/btcsuite/btcwallet v0.16.12 // indirect + github.com/btcsuite/btcwallet v0.16.13 // indirect github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 // indirect github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 // indirect github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5 // indirect - github.com/btcsuite/btcwallet/wtxmgr v1.5.4 // indirect + github.com/btcsuite/btcwallet/wtxmgr v1.5.6 // indirect github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect github.com/btcsuite/winsvc v1.0.0 // indirect @@ -144,7 +144,7 @@ require ( github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect github.com/lightningnetwork/lnd/healthcheck v1.2.6 // indirect github.com/lightningnetwork/lnd/queue v1.1.1 // indirect - github.com/lightningnetwork/lnd/sqldb v1.0.7 // indirect + github.com/lightningnetwork/lnd/sqldb v1.0.9 // indirect github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -238,3 +238,7 @@ replace ( replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display go 1.23.6 + +replace github.com/lightninglabs/lndclient => github.com/ellemouton/lndclient v1.0.1-0.20250420083827-f6ba7f319771 + +replace github.com/lightningnetwork/lnd => github.com/ellemouton/lnd v0.8.0-beta-rc3.0.20250420082546-0054b82f488c diff --git a/go.sum b/go.sum index a3446f79e..e20c956e9 100644 --- a/go.sum +++ b/go.sum @@ -674,18 +674,18 @@ github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhw github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 h1:oCjIcinPt7XQ644MP/22JcjYEC84qRc3bRBH0d7Hhd4= github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.16.12 h1:9SREKY892i1xTGlGLcu6x7O+WSQFn6+uQrSuskAOqh0= -github.com/btcsuite/btcwallet v0.16.12/go.mod h1:jBn+ThFrx/QqW0nXiGvXtJytju4aVoW7C0hY4s/+9vo= +github.com/btcsuite/btcwallet v0.16.13 h1:JGu+wrihQ0I00ODb3w92JtBPbrHxZhbcvU01O+e+lKw= +github.com/btcsuite/btcwallet v0.16.13/go.mod h1:H6dfoZcWPonM2wbVsR2ZBY0PKNZKdQyLAmnX8vL9JFA= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU= github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk= github.com/btcsuite/btcwallet/wallet/txrules v1.2.2/go.mod h1:4v+grppsDpVn91SJv+mZT7B8hEV4nSmpREM4I8Uohws= github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5 h1:93o5Xz9dYepBP4RMFUc9RGIFXwqP2volSWRkYJFrNtI= github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5/go.mod h1:lQ+e9HxZ85QP7r3kdxItkiMSloSLg1PEGis5o5CXUQw= -github.com/btcsuite/btcwallet/walletdb v1.4.4 h1:BDel6iT/ltYSIYKs0YbjwnEDi7xR3yzABIsQxN2F1L8= -github.com/btcsuite/btcwallet/walletdb v1.4.4/go.mod h1:jk/hvpLFINF0C1kfTn0bfx2GbnFT+Nvnj6eblZALfjs= -github.com/btcsuite/btcwallet/wtxmgr v1.5.4 h1:hJjHy1h/dJwSfD9uDsCwcH21D1iOrus6OrI5gR9E/O0= -github.com/btcsuite/btcwallet/wtxmgr v1.5.4/go.mod h1:lAv0b1Vj9Ig5U8QFm0yiJ9WqPl8yGO/6l7JxdHY1PKE= +github.com/btcsuite/btcwallet/walletdb v1.5.1 h1:HgMhDNCrtEFPC+8q0ei5DQ5U9Tl4RCspA22DEKXlopI= +github.com/btcsuite/btcwallet/walletdb v1.5.1/go.mod h1:jk/hvpLFINF0C1kfTn0bfx2GbnFT+Nvnj6eblZALfjs= +github.com/btcsuite/btcwallet/wtxmgr v1.5.6 h1:Zwvr/rrJYdOLqdBCSr4eICEstnEA+NBUvjIWLkrXaYI= +github.com/btcsuite/btcwallet/wtxmgr v1.5.6/go.mod h1:lzVbDkk/jRao2ib5kge46aLZW1yFc8RFNycdYpnsmZA= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= @@ -782,6 +782,10 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/ellemouton/lnd v0.8.0-beta-rc3.0.20250420082546-0054b82f488c h1:s7MHib5gBaRubKGT46Q5ikPCf1lMM+gAGdDKTIuDBuI= +github.com/ellemouton/lnd v0.8.0-beta-rc3.0.20250420082546-0054b82f488c/go.mod h1:BP+neeFpmeAA7o5hu3zp3FwOEl26idSyPV9zBOavp6E= +github.com/ellemouton/lndclient v1.0.1-0.20250420083827-f6ba7f319771 h1:EgF9pA37S4M9rIJJFJjB63KzskWEDjcpNtkfM8gngGA= +github.com/ellemouton/lndclient v1.0.1-0.20250420083827-f6ba7f319771/go.mod h1:TK2XVsbgbZAgkWisTyHQOhrAt7gs7iqjXqQ+C9FzzrU= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -1161,8 +1165,6 @@ github.com/lightninglabs/lightning-node-connect v0.3.3-alpha.0.20250306111457-ca github.com/lightninglabs/lightning-node-connect v0.3.3-alpha.0.20250306111457-cad4234830cc/go.mod h1:yrfNoMrGcWljHoQ31+dCSc0R7mBdYqISQeZABlrdkz4= github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY= github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4= -github.com/lightninglabs/lndclient v0.19.0-3 h1:PGGlDaz8x1dXGowDfAWhbuDqXTKNaJyb7SOTrRdG1es= -github.com/lightninglabs/lndclient v0.19.0-3/go.mod h1:5YMrFx00NvcmUHGZRxT4Qw/gOfR5x50/ReJmJ6w0yVk= github.com/lightninglabs/loop v0.29.0-beta.rc2.0.20250306160707-1091a628755c h1:Ox7SfusBRizc7tOKy9HKXodR7rcvpko08EH9aP/+euQ= github.com/lightninglabs/loop v0.29.0-beta.rc2.0.20250306160707-1091a628755c/go.mod h1:IzzOw/v4VwKmotJrmPyM8P+FPZ/XBbxa4u2JuDYrtAU= github.com/lightninglabs/loop/looprpc v1.0.4-0.20250306160707-1091a628755c h1:ueEVZjeUKI3CoTJAdpDbXKHTSd9OfY8OPqTDBjeHhfs= @@ -1185,8 +1187,6 @@ github.com/lightninglabs/taproot-assets v0.5.2-0.20250401150538-a9ea76a9ed3c h1: github.com/lightninglabs/taproot-assets v0.5.2-0.20250401150538-a9ea76a9ed3c/go.mod h1:e3SjXbbi4xKhOzq54c672Z/j9UTRq5DLJGx/URgVTJo= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= -github.com/lightningnetwork/lnd v0.19.0-beta.rc1.0.20250327183348-eb822a5e117f h1:+Bejv2Ij/ryUjLacBd5au0acMH0AYs0lhb7ki5rx9ms= -github.com/lightningnetwork/lnd v0.19.0-beta.rc1.0.20250327183348-eb822a5e117f/go.mod h1:BP+neeFpmeAA7o5hu3zp3FwOEl26idSyPV9zBOavp6E= github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI= github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U= github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0= @@ -1197,12 +1197,12 @@ github.com/lightningnetwork/lnd/fn/v2 v2.0.8 h1:r2SLz7gZYQPVc3IZhU82M66guz3Zk2oY github.com/lightningnetwork/lnd/fn/v2 v2.0.8/go.mod h1:TOzwrhjB/Azw1V7aa8t21ufcQmdsQOQMDtxVOQWNl8s= github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI= github.com/lightningnetwork/lnd/healthcheck v1.2.6/go.mod h1:Mu02um4CWY/zdTOvFje7WJgJcHyX2zq/FG3MhOAiGaQ= -github.com/lightningnetwork/lnd/kvdb v1.4.13 h1:fe3sFBxsgcXl16G1zj6O/wZf0hbBHOxFe8pCgmnHZxM= -github.com/lightningnetwork/lnd/kvdb v1.4.13/go.mod h1:1y0Z81CGQu4SMpcnAie/oK4tzgEqFQqFdj6k3fz2s8s= +github.com/lightningnetwork/lnd/kvdb v1.4.15 h1:3eN6uGcubvGB5itPp1D0D4uEEkIMYht3w0LDnqLzAWI= +github.com/lightningnetwork/lnd/kvdb v1.4.15/go.mod h1:HW+bvwkxNaopkz3oIgBV6NEnV4jCEZCACFUcNg4xSjM= github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI= github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4= -github.com/lightningnetwork/lnd/sqldb v1.0.7 h1:wQ4DdHY++uwxwth2CHL7s+duGqmMLaoIRBOQCa9HPTk= -github.com/lightningnetwork/lnd/sqldb v1.0.7/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4= +github.com/lightningnetwork/lnd/sqldb v1.0.9 h1:7OHi+Hui823mB/U9NzCdlZTAGSVdDCbjp33+6d/Q+G0= +github.com/lightningnetwork/lnd/sqldb v1.0.9/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4= github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM= github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA= github.com/lightningnetwork/lnd/tlv v1.3.0 h1:exS/KCPEgpOgviIttfiXAPaUqw2rHQrnUOpP7HPBPiY= From be018e8db1952a83e13108e93f2fc2e1aa3f0b3f Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Sun, 20 Apr 2025 11:09:38 +0200 Subject: [PATCH 3/3] firewall: extract session ID from metadata --- firewall/privacy_mapper.go | 6 +++-- firewall/request_info.go | 45 ++++++++++++++++++++++++++++++++++++++ firewall/request_logger.go | 33 ++++++++++++++++++++-------- firewall/rule_enforcer.go | 6 +++-- 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/firewall/privacy_mapper.go b/firewall/privacy_mapper.go index cbd8a8da4..ad1356016 100644 --- a/firewall/privacy_mapper.go +++ b/firewall/privacy_mapper.go @@ -106,9 +106,11 @@ func (p *PrivacyMapper) Intercept(ctx context.Context, "interception request: %v", err) } - sessionID, err := session.IDFromMacaroon(ri.Macaroon) + sessionID, ok, err := ri.extractSessionID() if err != nil { - return nil, fmt.Errorf("could not extract ID from macaroon") + return nil, fmt.Errorf("could not extract session ID: %v", err) + } else if !ok { + return nil, fmt.Errorf("no session ID found in request") } log.Tracef("PrivacyMapper: Intercepting %v", ri) diff --git a/firewall/request_info.go b/firewall/request_info.go index 10a524934..ae98ed11b 100644 --- a/firewall/request_info.go +++ b/firewall/request_info.go @@ -4,7 +4,9 @@ import ( "fmt" "strings" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/lnrpc" + "google.golang.org/grpc/metadata" "gopkg.in/macaroon.v2" ) @@ -38,11 +40,19 @@ type RequestInfo struct { MetaInfo *InterceptMetaInfo Rules *InterceptRules WithPrivacy bool + MDPairs metadata.MD } // NewInfoFromRequest parses the given RPC middleware interception request and // returns a RequestInfo struct. func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) { + md := make(metadata.MD) + for k, vs := range req.MetadataPairs { + for _, v := range vs.Values { + md.Append(k, v) + } + } + var ri *RequestInfo switch t := req.InterceptType.(type) { case *lnrpc.RPCMiddlewareRequest_StreamAuth: @@ -50,6 +60,7 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) { MWRequestType: MWRequestTypeStreamAuth, URI: t.StreamAuth.MethodFullUri, Streaming: true, + MDPairs: md, } case *lnrpc.RPCMiddlewareRequest_Request: @@ -60,6 +71,7 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) { IsError: t.Request.IsError, Serialized: t.Request.Serialized, Streaming: t.Request.StreamRpc, + MDPairs: md, } case *lnrpc.RPCMiddlewareRequest_Response: @@ -70,6 +82,7 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) { IsError: t.Response.IsError, Serialized: t.Response.Serialized, Streaming: t.Response.StreamRpc, + MDPairs: md, } default: @@ -134,3 +147,35 @@ func (ri *RequestInfo) String() string { ri.GRPCMessageType, ri.Streaming, strings.Join(ri.Caveats, ","), ri.MetaInfo, ri.Rules) } + +func (ri *RequestInfo) extractSessionID() (session.ID, bool, error) { + // First prize is to extract the session ID from the MD pairs. + id, ok, err := session.FromGrpcMD(ri.MDPairs) + if err != nil { + return id, ok, err + } else if ok { + return id, ok, nil + } + + // TODO(elle): This is a temporary workaround to support older versions + // of LND that don't attach metadata pairs to the request. + // We should remove this once we have bumped our minimum compatible + // LND version to one that always attaches metadata pairs. + // This is because the macaroon root key ID is not a reliable way of + // extracting the session ID since the macaroon root key ID may also + // be the first 4 bytes of an account ID and so collisions are possible + // here. + + // Otherwise, fall back to extracting the session ID from the macaroon. + if ri.Macaroon == nil { + return session.ID{}, false, nil + } + + id, err = session.IDFromMacaroon(ri.Macaroon) + if err != nil { + return session.ID{}, false, fmt.Errorf("could not extract "+ + "ID from macaroon: %w", err) + } + + return id, true, nil +} diff --git a/firewall/request_logger.go b/firewall/request_logger.go index dad96339b..db2da2699 100644 --- a/firewall/request_logger.go +++ b/firewall/request_logger.go @@ -182,15 +182,30 @@ func (r *RequestLogger) Intercept(_ context.Context, func (r *RequestLogger) addNewAction(ri *RequestInfo, withPayloadData bool) error { - // If no macaroon is provided, then an empty 4-byte array is used as the - // session ID. Otherwise, the macaroon is used to derive a session ID. - var sessionID [4]byte - if ri.Macaroon != nil { - var err error - sessionID, err = session.IDFromMacaroon(ri.Macaroon) - if err != nil { - return fmt.Errorf("could not extract ID from macaroon") - } + // NOTE: Here is where we determine if we are linking the action to a + // known session OR a known account OR both. Right now (to not change + // behaviour from before): we give preference to a linked session. + // The original behaviour here was to purely use the macaroon's + // root key ID (4 bytes) to extract the "session ID". BUT if this + // action was triggered by an account call (that is not coupled to a + // session), then the "session ID" we are extracting here is actually + // the first 4 bytes of the account ID. + // + // What we actually need to do is: + // 1) only use the ctx/metadata to extract the session ID. + // 2) use the macaroon caveat to extract the account ID. + // With the above complete, we will be able to link an action to: + // a session OR an account OR both OR none. + // + // Given the above info, it is also clear that the name "session ID" + // here is misleading as it is not necessarily the session ID. It could + // be: a session ID, an account ID or None. So it is more like a + // "macaroon identifier". + var sessionID session.ID + if sessID, ok, err := ri.extractSessionID(); err != nil { + return fmt.Errorf("could not extract session ID: %v", err) + } else if ok { + sessionID = sessID } action := &firewalldb.Action{ diff --git a/firewall/rule_enforcer.go b/firewall/rule_enforcer.go index 7914965ed..2e78b152a 100644 --- a/firewall/rule_enforcer.go +++ b/firewall/rule_enforcer.go @@ -233,9 +233,11 @@ func (r *RuleEnforcer) Intercept(ctx context.Context, func (r *RuleEnforcer) handleRequest(ctx context.Context, ri *RequestInfo) (proto.Message, error) { - sessionID, err := session.IDFromMacaroon(ri.Macaroon) + sessionID, ok, err := ri.extractSessionID() if err != nil { - return nil, fmt.Errorf("could not extract ID from macaroon") + return nil, fmt.Errorf("could not extract session ID: %v", err) + } else if !ok { + return nil, fmt.Errorf("no session ID found in request") } rules, err := r.collectEnforcers(ctx, ri, sessionID)