Skip to content

Commit dc90f6d

Browse files
committed
firewall: obfuscate BatchOpenChannel
We obfuscate fields from the batch channel open requests and responses.
1 parent 4d2eec9 commit dc90f6d

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

firewall/privacy_mapper.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,13 @@ func (p *PrivacyMapper) checkers(db firewalldb.PrivacyMapDB,
296296
handleClosedChannelsResponse(db, flags, p.randIntn),
297297
mid.PassThroughErrorHandler,
298298
),
299+
"/lnrpc.Lightning/BatchOpenChannel": mid.NewFullRewriter(
300+
&lnrpc.BatchOpenChannelRequest{},
301+
&lnrpc.BatchOpenChannelResponse{},
302+
handleBatchOpenChannelRequest(db, flags),
303+
handleBatchOpenChannelResponse(db, flags),
304+
mid.PassThroughErrorHandler,
305+
),
299306
}
300307
}
301308

@@ -1106,6 +1113,127 @@ func handleClosedChannelsResponse(db firewalldb.PrivacyMapDB,
11061113
}
11071114
}
11081115

1116+
func handleBatchOpenChannelRequest(db firewalldb.PrivacyMapDB,
1117+
flags session.PrivacyFlags) func(ctx context.Context,
1118+
r *lnrpc.BatchOpenChannelRequest) (proto.Message, error) {
1119+
1120+
return func(_ context.Context, r *lnrpc.BatchOpenChannelRequest) (
1121+
proto.Message, error) {
1122+
1123+
var reqs = make([]*lnrpc.BatchOpenChannel, len(r.Channels))
1124+
1125+
err := db.Update(func(tx firewalldb.PrivacyMapTx) error {
1126+
for i, c := range r.Channels {
1127+
var err error
1128+
1129+
// Note, this only works if the obfuscated
1130+
// pubkey was already created via other
1131+
// calls, e.g. via ListChannels or
1132+
// GetInfo or the like.
1133+
nodePubkey := c.NodePubkey
1134+
if !flags.Contains(session.ClearPubkeys) {
1135+
nodePubkey, err = firewalldb.RevealBytes(
1136+
tx, c.NodePubkey,
1137+
)
1138+
if err != nil {
1139+
return err
1140+
}
1141+
}
1142+
1143+
reqs[i] = &lnrpc.BatchOpenChannel{
1144+
// Obfuscated fields.
1145+
NodePubkey: nodePubkey,
1146+
1147+
// Non-obfuscated fields.
1148+
LocalFundingAmount: c.LocalFundingAmount,
1149+
PushSat: c.PushSat,
1150+
Private: c.Private,
1151+
MinHtlcMsat: c.MinHtlcMsat,
1152+
RemoteCsvDelay: c.RemoteCsvDelay,
1153+
CloseAddress: c.CloseAddress,
1154+
PendingChanId: c.PendingChanId,
1155+
CommitmentType: c.CommitmentType,
1156+
RemoteMaxValueInFlightMsat: c.RemoteMaxValueInFlightMsat,
1157+
RemoteMaxHtlcs: c.RemoteMaxHtlcs,
1158+
MaxLocalCsv: c.MaxLocalCsv,
1159+
ZeroConf: c.ZeroConf,
1160+
ScidAlias: c.ScidAlias,
1161+
BaseFee: c.BaseFee,
1162+
FeeRate: c.FeeRate,
1163+
UseBaseFee: c.UseBaseFee,
1164+
UseFeeRate: c.UseFeeRate,
1165+
RemoteChanReserveSat: c.RemoteChanReserveSat,
1166+
Memo: c.Memo,
1167+
}
1168+
}
1169+
1170+
return nil
1171+
})
1172+
if err != nil {
1173+
return nil, err
1174+
}
1175+
1176+
return &lnrpc.BatchOpenChannelRequest{
1177+
Channels: reqs,
1178+
TargetConf: r.TargetConf,
1179+
SatPerVbyte: r.SatPerVbyte,
1180+
MinConfs: r.MinConfs,
1181+
SpendUnconfirmed: r.SpendUnconfirmed,
1182+
Label: r.Label,
1183+
}, nil
1184+
}
1185+
}
1186+
1187+
func handleBatchOpenChannelResponse(db firewalldb.PrivacyMapDB,
1188+
flags session.PrivacyFlags) func(ctx context.Context,
1189+
r *lnrpc.BatchOpenChannelResponse) (proto.Message, error) {
1190+
1191+
return func(_ context.Context, r *lnrpc.BatchOpenChannelResponse) (
1192+
proto.Message, error) {
1193+
1194+
resps := make([]*lnrpc.PendingUpdate, len(r.PendingChannels))
1195+
1196+
err := db.Update(func(tx firewalldb.PrivacyMapTx) error {
1197+
for i, p := range r.PendingChannels {
1198+
var (
1199+
txIdBytes = p.Txid
1200+
outputIndex = p.OutputIndex
1201+
)
1202+
1203+
if !flags.Contains(session.ClearChanIDs) {
1204+
txIDStr := hex.EncodeToString(p.Txid)
1205+
txID, outIdx, err := firewalldb.HideChanPoint(
1206+
tx, txIDStr, p.OutputIndex,
1207+
)
1208+
if err != nil {
1209+
return err
1210+
}
1211+
outputIndex = outIdx
1212+
1213+
txIdBytes, err = hex.DecodeString(txID)
1214+
if err != nil {
1215+
return err
1216+
}
1217+
}
1218+
1219+
resps[i] = &lnrpc.PendingUpdate{
1220+
Txid: txIdBytes,
1221+
OutputIndex: outputIndex,
1222+
}
1223+
}
1224+
1225+
return nil
1226+
})
1227+
if err != nil {
1228+
return nil, err
1229+
}
1230+
1231+
return &lnrpc.BatchOpenChannelResponse{
1232+
PendingChannels: resps,
1233+
}, nil
1234+
}
1235+
}
1236+
11091237
// maybeHideAmount hides an amount if the privacy flag is not set.
11101238
func maybeHideAmount(flags session.PrivacyFlags, randIntn func(int) (int, error),
11111239
a int64) (int64, error) {

firewall/privacy_mapper_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package firewall
22

33
import (
44
"context"
5+
"encoding/hex"
56
"encoding/json"
67
"fmt"
78
"testing"
@@ -27,8 +28,12 @@ func TestPrivacyMapper(t *testing.T) {
2728

2829
// Define some transaction outpoints used for mapping.
2930
clearTxID := "abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd"
31+
clearTxIDBytes, err := hex.DecodeString(clearTxID)
32+
require.NoError(t, err)
3033

3134
obfusTxID0 := "097ef666a61919ff3413b3b701eae3a5cbac08f70c0ca567806e1fa6acbfe384"
35+
obfusTxID0Bytes, err := hex.DecodeString(obfusTxID0)
36+
require.NoError(t, err)
3237
obfusOut0 := uint32(2161781494)
3338
obfusTxID0Reversed, err := chainhash.NewHashFromStr(obfusTxID0)
3439
require.NoError(t, err)
@@ -474,6 +479,59 @@ func TestPrivacyMapper(t *testing.T) {
474479
},
475480
},
476481
},
482+
{
483+
name: "BatchOpenChannel Request",
484+
uri: "/lnrpc.Lightning/BatchOpenChannel",
485+
msgType: rpcperms.TypeRequest,
486+
msg: &lnrpc.BatchOpenChannelRequest{
487+
TargetConf: 6,
488+
Channels: []*lnrpc.BatchOpenChannel{
489+
{
490+
NodePubkey: []byte{
491+
200, 19, 68, 149,
492+
},
493+
LocalFundingAmount: 1_000_000,
494+
PushSat: 1_000_000,
495+
MinHtlcMsat: 100,
496+
},
497+
},
498+
},
499+
expectedReplacement: &lnrpc.BatchOpenChannelRequest{
500+
TargetConf: 6,
501+
Channels: []*lnrpc.BatchOpenChannel{
502+
{
503+
NodePubkey: []byte{
504+
1, 2, 3, 4,
505+
},
506+
LocalFundingAmount: 1_000_000,
507+
PushSat: 1_000_000,
508+
MinHtlcMsat: 100,
509+
},
510+
},
511+
},
512+
},
513+
{
514+
name: "BatchOpenChannel Response",
515+
uri: "/lnrpc.Lightning/BatchOpenChannel",
516+
msgType: rpcperms.TypeResponse,
517+
msg: &lnrpc.BatchOpenChannelResponse{
518+
PendingChannels: []*lnrpc.PendingUpdate{
519+
{
520+
521+
Txid: clearTxIDBytes,
522+
OutputIndex: 0,
523+
},
524+
},
525+
},
526+
expectedReplacement: &lnrpc.BatchOpenChannelResponse{
527+
PendingChannels: []*lnrpc.PendingUpdate{
528+
{
529+
Txid: obfusTxID0Bytes,
530+
OutputIndex: obfusOut0,
531+
},
532+
},
533+
},
534+
},
477535
}
478536

479537
decodedID := &lnrpc.MacaroonId{

0 commit comments

Comments
 (0)