mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
firewall+firewalldb: add SessionDB interface
SessionDB is an interface that gives helper methods for how privacy mapping should be done. A mock for SessionDB is added to save on some code repetition, the privacy flags functionality is used in a later test.
This commit is contained in:
parent
1e83df2225
commit
cb542a5015
7 changed files with 130 additions and 112 deletions
|
|
@ -59,21 +59,21 @@ var _ mid.RequestInterceptor = (*PrivacyMapper)(nil)
|
|||
// PrivacyMapper is a RequestInterceptor that maps any pseudo names in certain
|
||||
// requests to their real values and vice versa for responses.
|
||||
type PrivacyMapper struct {
|
||||
newDB firewalldb.NewPrivacyMapDB
|
||||
randIntn func(int) (int, error)
|
||||
sessionIDIndexDB session.IDToGroupIndex
|
||||
newDB firewalldb.NewPrivacyMapDB
|
||||
randIntn func(int) (int, error)
|
||||
sessionDB firewalldb.SessionDB
|
||||
}
|
||||
|
||||
// NewPrivacyMapper returns a new instance of PrivacyMapper. The randIntn
|
||||
// function is used to draw randomness for request field obfuscation.
|
||||
func NewPrivacyMapper(newDB firewalldb.NewPrivacyMapDB,
|
||||
randIntn func(int) (int, error),
|
||||
sessionIDIndexDB session.IDToGroupIndex) *PrivacyMapper {
|
||||
sessionDB firewalldb.SessionDB) *PrivacyMapper {
|
||||
|
||||
return &PrivacyMapper{
|
||||
newDB: newDB,
|
||||
randIntn: randIntn,
|
||||
sessionIDIndexDB: sessionIDIndexDB,
|
||||
newDB: newDB,
|
||||
randIntn: randIntn,
|
||||
sessionDB: sessionDB,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ func (p *PrivacyMapper) Intercept(ctx context.Context,
|
|||
}
|
||||
|
||||
// Get group ID for session ID.
|
||||
groupID, err := p.sessionIDIndexDB.GetGroupID(sessionID)
|
||||
groupID, err := p.sessionDB.GetGroupID(sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package firewall
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -292,17 +291,18 @@ func TestPrivacyMapper(t *testing.T) {
|
|||
"01020304": "c8134495",
|
||||
}
|
||||
|
||||
db := newMockDB(t, mapPreloadRealToPseudo, sessionID)
|
||||
|
||||
err = db.AddSessionAndGroupIDPair(sessionID, sessionID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// randIntn is used for deterministic testing.
|
||||
randIntn := func(n int) (int, error) { return 100, nil }
|
||||
p := NewPrivacyMapper(db.NewSessionDB, randIntn, db)
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// Initialize privacy mapping.
|
||||
db := newMockDB(t, mapPreloadRealToPseudo, sessionID)
|
||||
|
||||
pd := firewalldb.NewMockSessionDB()
|
||||
pd.AddPair(sessionID, sessionID)
|
||||
|
||||
// randIntn is used for deterministic testing.
|
||||
randIntn := func(n int) (int, error) { return 100, nil }
|
||||
p := NewPrivacyMapper(db.NewSessionDB, randIntn, pd)
|
||||
|
||||
rawMsg, err := proto.Marshal(test.msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -341,6 +341,12 @@ func TestPrivacyMapper(t *testing.T) {
|
|||
|
||||
// Subtest to test behavior with real randomness.
|
||||
t.Run("Response with randomness", func(t *testing.T) {
|
||||
// Initialize privacy mapping.
|
||||
db := newMockDB(t, mapPreloadRealToPseudo, sessionID)
|
||||
|
||||
pd := firewalldb.NewMockSessionDB()
|
||||
pd.AddPair(sessionID, sessionID)
|
||||
|
||||
msg := &lnrpc.ForwardingHistoryResponse{
|
||||
ForwardingEvents: []*lnrpc.ForwardingEvent{
|
||||
{
|
||||
|
|
@ -360,7 +366,7 @@ func TestPrivacyMapper(t *testing.T) {
|
|||
rawMsg, err := proto.Marshal(msg)
|
||||
require.NoError(t, err)
|
||||
|
||||
p = NewPrivacyMapper(db.NewSessionDB, CryptoRandIntn, db)
|
||||
p := NewPrivacyMapper(db.NewSessionDB, CryptoRandIntn, pd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We test the independent outgoing amount (incoming amount
|
||||
|
|
@ -373,7 +379,7 @@ func TestPrivacyMapper(t *testing.T) {
|
|||
// We keep track of the timestamp. We test only the timestamp in
|
||||
// seconds as there can be numerical inaccuracies with the
|
||||
// nanosecond one.
|
||||
timestamp := msg.ForwardingEvents[0].Timestamp
|
||||
timestamp := msg.ForwardingEvents[0].TimestampNs / 1e9
|
||||
timestampInterval := uint64(timeVariation) / 1e9
|
||||
minTime := timestamp - timestampInterval
|
||||
maxTime := timestamp + timestampInterval
|
||||
|
|
@ -447,19 +453,12 @@ func TestPrivacyMapper(t *testing.T) {
|
|||
|
||||
type mockDB struct {
|
||||
privDB map[string]*mockPrivacyMapDB
|
||||
|
||||
sessionIDIndex map[session.ID]session.ID
|
||||
groupIDIndex map[session.ID][]session.ID
|
||||
}
|
||||
|
||||
func newMockDB(t *testing.T, preloadRealToPseudo map[string]string,
|
||||
sessID session.ID) mockDB {
|
||||
|
||||
db := mockDB{
|
||||
privDB: make(map[string]*mockPrivacyMapDB),
|
||||
sessionIDIndex: make(map[session.ID]session.ID),
|
||||
groupIDIndex: make(map[session.ID][]session.ID),
|
||||
}
|
||||
db := mockDB{privDB: make(map[string]*mockPrivacyMapDB)}
|
||||
sessDB := db.NewSessionDB(sessID)
|
||||
|
||||
_ = sessDB.Update(func(tx firewalldb.PrivacyMapTx) error {
|
||||
|
|
@ -484,30 +483,6 @@ func (m mockDB) NewSessionDB(sessionID session.ID) firewalldb.PrivacyMapDB {
|
|||
return newDB
|
||||
}
|
||||
|
||||
func (m mockDB) AddSessionAndGroupIDPair(sessionID, groupID session.ID) error {
|
||||
m.sessionIDIndex[sessionID] = groupID
|
||||
m.groupIDIndex[groupID] = append(m.groupIDIndex[groupID], sessionID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m mockDB) GetGroupID(sessionID session.ID) (session.ID, error) {
|
||||
groupID, ok := m.sessionIDIndex[sessionID]
|
||||
if !ok {
|
||||
return session.ID{}, fmt.Errorf("group ID not found")
|
||||
}
|
||||
|
||||
return groupID, nil
|
||||
}
|
||||
|
||||
func (m mockDB) GetSessionIDs(groupID session.ID) ([]session.ID, error) {
|
||||
sessionIDs, ok := m.groupIDIndex[groupID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("group ID not found")
|
||||
}
|
||||
|
||||
return sessionIDs, nil
|
||||
}
|
||||
|
||||
func newMockPrivacyMapDB() *mockPrivacyMapDB {
|
||||
return &mockPrivacyMapDB{
|
||||
r2p: make(map[string]string),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ var _ mid.RequestInterceptor = (*RuleEnforcer)(nil)
|
|||
type RuleEnforcer struct {
|
||||
ruleDB firewalldb.RulesDB
|
||||
actionsDB firewalldb.ActionReadDBGetter
|
||||
sessionIDIndexDB session.IDToGroupIndex
|
||||
sessionDB firewalldb.SessionDB
|
||||
markActionErrored func(reqID uint64, reason string) error
|
||||
newPrivMap firewalldb.NewPrivacyMapDB
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ type featurePerms func(ctx context.Context) (map[string]map[string]bool, error)
|
|||
// NewRuleEnforcer constructs a new RuleEnforcer instance.
|
||||
func NewRuleEnforcer(ruleDB firewalldb.RulesDB,
|
||||
actionsDB firewalldb.ActionReadDBGetter,
|
||||
sessionIDIndex session.IDToGroupIndex,
|
||||
sessionIDIndex firewalldb.SessionDB,
|
||||
getFeaturePerms featurePerms, permsMgr *perms.Manager, nodeID [33]byte,
|
||||
routerClient lndclient.RouterClient,
|
||||
lndClient lndclient.LightningClient, ruleMgrs rules.ManagerSet,
|
||||
|
|
@ -70,7 +70,7 @@ func NewRuleEnforcer(ruleDB firewalldb.RulesDB,
|
|||
ruleMgrs: ruleMgrs,
|
||||
markActionErrored: markActionErrored,
|
||||
newPrivMap: privMap,
|
||||
sessionIDIndexDB: sessionIDIndex,
|
||||
sessionDB: sessionIDIndex,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ func (r *RuleEnforcer) handleRequest(ctx context.Context,
|
|||
return nil, fmt.Errorf("could not extract ID from macaroon")
|
||||
}
|
||||
|
||||
groupID, err := r.sessionIDIndexDB.GetGroupID(sessionID)
|
||||
groupID, err := r.sessionDB.GetGroupID(sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -269,7 +269,7 @@ func (r *RuleEnforcer) handleResponse(ctx context.Context,
|
|||
return nil, fmt.Errorf("could not extract ID from macaroon")
|
||||
}
|
||||
|
||||
groupID, err := r.sessionIDIndexDB.GetGroupID(sessionID)
|
||||
groupID, err := r.sessionDB.GetGroupID(sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -308,7 +308,7 @@ func (r *RuleEnforcer) handleErrorResponse(ctx context.Context,
|
|||
return nil, fmt.Errorf("could not extract ID from macaroon")
|
||||
}
|
||||
|
||||
groupID, err := r.sessionIDIndexDB.GetGroupID(sessionID)
|
||||
groupID, err := r.sessionDB.GetGroupID(sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -346,9 +345,9 @@ func TestListGroupActions(t *testing.T) {
|
|||
group1 := intToSessionID(0)
|
||||
|
||||
// Link session 1 and session 2 to group 1.
|
||||
index := newMockSessionIDIndex()
|
||||
index.addPair(sessionID1, group1)
|
||||
index.addPair(sessionID2, group1)
|
||||
index := NewMockSessionDB()
|
||||
index.AddPair(sessionID1, group1)
|
||||
index.AddPair(sessionID2, group1)
|
||||
|
||||
db, err := NewDB(t.TempDir(), "test.db", index)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -382,48 +381,3 @@ func TestListGroupActions(t *testing.T) {
|
|||
require.Equal(t, sessionID1, al[0].SessionID)
|
||||
require.Equal(t, sessionID2, al[1].SessionID)
|
||||
}
|
||||
|
||||
type mockSessionIDIndex struct {
|
||||
sessionToGroupID map[session.ID]session.ID
|
||||
groupToSessionIDs map[session.ID][]session.ID
|
||||
}
|
||||
|
||||
var _ session.IDToGroupIndex = (*mockSessionIDIndex)(nil)
|
||||
|
||||
func newMockSessionIDIndex() *mockSessionIDIndex {
|
||||
return &mockSessionIDIndex{
|
||||
sessionToGroupID: make(map[session.ID]session.ID),
|
||||
groupToSessionIDs: make(map[session.ID][]session.ID),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockSessionIDIndex) addPair(sessionID, groupID session.ID) {
|
||||
m.sessionToGroupID[sessionID] = groupID
|
||||
|
||||
m.groupToSessionIDs[groupID] = append(
|
||||
m.groupToSessionIDs[groupID], sessionID,
|
||||
)
|
||||
}
|
||||
|
||||
func (m *mockSessionIDIndex) GetGroupID(sessionID session.ID) (session.ID,
|
||||
error) {
|
||||
|
||||
id, ok := m.sessionToGroupID[sessionID]
|
||||
if !ok {
|
||||
return session.ID{}, fmt.Errorf("no group ID found for " +
|
||||
"session ID")
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (m *mockSessionIDIndex) GetSessionIDs(groupID session.ID) ([]session.ID,
|
||||
error) {
|
||||
|
||||
ids, ok := m.groupToSessionIDs[groupID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no session IDs found for group ID")
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
|
|
@ -42,13 +41,11 @@ var (
|
|||
type DB struct {
|
||||
*bbolt.DB
|
||||
|
||||
sessionIDIndex session.IDToGroupIndex
|
||||
sessionIDIndex SessionDB
|
||||
}
|
||||
|
||||
// NewDB creates a new bolt database that can be found at the given directory.
|
||||
func NewDB(dir, fileName string, sessionIDIndex session.IDToGroupIndex) (*DB,
|
||||
error) {
|
||||
|
||||
func NewDB(dir, fileName string, sessionIDIndex SessionDB) (*DB, error) {
|
||||
firstInit := false
|
||||
path := filepath.Join(dir, fileName)
|
||||
|
||||
|
|
|
|||
12
firewalldb/interface.go
Normal file
12
firewalldb/interface.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package firewalldb
|
||||
|
||||
import "github.com/lightninglabs/lightning-terminal/session"
|
||||
|
||||
// SessionDB is an interface that abstracts the database operations needed for
|
||||
// the privacy mapper to function.
|
||||
type SessionDB interface {
|
||||
session.IDToGroupIndex
|
||||
|
||||
// GetSessionByID returns the session for a specific id.
|
||||
GetSessionByID(session.ID) (*session.Session, error)
|
||||
}
|
||||
80
firewalldb/mock.go
Normal file
80
firewalldb/mock.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package firewalldb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
)
|
||||
|
||||
type mockSessionDB struct {
|
||||
sessionToGroupID map[session.ID]session.ID
|
||||
groupToSessionIDs map[session.ID][]session.ID
|
||||
privacyFlags map[session.ID]session.PrivacyFlags
|
||||
}
|
||||
|
||||
var _ SessionDB = (*mockSessionDB)(nil)
|
||||
|
||||
// NewMockSessionDB creates a new mock privacy map details instance.
|
||||
func NewMockSessionDB() *mockSessionDB {
|
||||
return &mockSessionDB{
|
||||
sessionToGroupID: make(map[session.ID]session.ID),
|
||||
groupToSessionIDs: make(map[session.ID][]session.ID),
|
||||
privacyFlags: make(map[session.ID]session.PrivacyFlags),
|
||||
}
|
||||
}
|
||||
|
||||
// AddPair adds a new session to group ID pair to the mock details.
|
||||
func (m *mockSessionDB) AddPair(sessionID, groupID session.ID) {
|
||||
m.sessionToGroupID[sessionID] = groupID
|
||||
|
||||
m.groupToSessionIDs[groupID] = append(
|
||||
m.groupToSessionIDs[groupID], sessionID,
|
||||
)
|
||||
}
|
||||
|
||||
// GetGroupID returns the group ID for the given session ID.
|
||||
func (m *mockSessionDB) GetGroupID(sessionID session.ID) (session.ID, error) {
|
||||
id, ok := m.sessionToGroupID[sessionID]
|
||||
if !ok {
|
||||
return session.ID{}, fmt.Errorf("no group ID found for " +
|
||||
"session ID")
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetSessionIDs returns the set of session IDs that are in the group
|
||||
func (m *mockSessionDB) GetSessionIDs(groupID session.ID) ([]session.ID, error) {
|
||||
ids, ok := m.groupToSessionIDs[groupID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no session IDs found for group ID")
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// GetSessionByID returns the session for a specific id.
|
||||
func (m *mockSessionDB) GetSessionByID(sessionID session.ID) (*session.Session,
|
||||
error) {
|
||||
|
||||
s, ok := m.sessionToGroupID[sessionID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no session found for session ID")
|
||||
}
|
||||
|
||||
f, ok := m.privacyFlags[sessionID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no privacy flags found for session ID")
|
||||
}
|
||||
|
||||
return &session.Session{GroupID: s, PrivacyFlags: f}, nil
|
||||
}
|
||||
|
||||
// AddPrivacyFlags is a helper that adds privacy flags to the mock session db.
|
||||
func (m *mockSessionDB) AddPrivacyFlags(sessionID session.ID,
|
||||
flags session.PrivacyFlags) error {
|
||||
|
||||
m.privacyFlags[sessionID] = flags
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue