Skip to content

Commit a6136fd

Browse files
committed
firewalldb: plug in sql priv map
In this commit, we introduce the SQL impl of the privacy mapper store. The privacy mapper unit tests can now be run against the SQL impl.
1 parent 3578cc6 commit a6136fd

File tree

3 files changed

+183
-13
lines changed

3 files changed

+183
-13
lines changed

firewalldb/privacy_mapper_sql.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package firewalldb
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"errors"
7+
8+
"github.com/lightninglabs/lightning-terminal/db/sqlc"
9+
"github.com/lightninglabs/lightning-terminal/session"
10+
)
11+
12+
// SQLPrivacyPairQueries is a subset of the sqlc.Queries interface that can be
13+
// used to interact with the privacy map table.
14+
//
15+
//nolint:lll
16+
type SQLPrivacyPairQueries interface {
17+
SQLSessionQueries
18+
19+
InsertPrivacyPair(ctx context.Context, arg sqlc.InsertPrivacyPairParams) error
20+
GetAllPrivacyPairs(ctx context.Context, groupID int64) ([]sqlc.GetAllPrivacyPairsRow, error)
21+
GetPseudoForReal(ctx context.Context, arg sqlc.GetPseudoForRealParams) (string, error)
22+
GetRealForPseudo(ctx context.Context, arg sqlc.GetRealForPseudoParams) (string, error)
23+
}
24+
25+
// PrivacyDB constructs a PrivacyMapDB that will be indexed under the given
26+
// group ID key.
27+
func (s *SQLDB) PrivacyDB(groupID session.ID) PrivacyMapDB {
28+
return &sqlExecutor[PrivacyMapTx]{
29+
db: s.db,
30+
wrapTx: func(queries SQLQueries) PrivacyMapTx {
31+
return &privacyMapSQLTx{
32+
queries: queries,
33+
groupID: groupID,
34+
}
35+
},
36+
}
37+
}
38+
39+
// privacyMapSQLTx is an implementation of PrivacyMapTx.
40+
type privacyMapSQLTx struct {
41+
queries SQLQueries
42+
groupID session.ID
43+
}
44+
45+
// NewPair inserts a new real-pseudo pair into the db.
46+
//
47+
// NOTE: this is part of the PrivacyMapTx interface.
48+
func (p *privacyMapSQLTx) NewPair(ctx context.Context, real,
49+
pseudo string) error {
50+
51+
groupID, err := p.getGroupID(ctx)
52+
if err != nil {
53+
return err
54+
}
55+
56+
_, err = p.queries.GetPseudoForReal(ctx, sqlc.GetPseudoForRealParams{
57+
GroupID: groupID,
58+
RealVal: real,
59+
})
60+
if err == nil {
61+
return ErrDuplicateRealValue
62+
} else if !errors.Is(err, sql.ErrNoRows) {
63+
return err
64+
}
65+
66+
_, err = p.queries.GetRealForPseudo(ctx, sqlc.GetRealForPseudoParams{
67+
GroupID: groupID,
68+
PseudoVal: pseudo,
69+
})
70+
if err == nil {
71+
return ErrDuplicatePseudoValue
72+
} else if !errors.Is(err, sql.ErrNoRows) {
73+
return err
74+
}
75+
76+
return p.queries.InsertPrivacyPair(ctx, sqlc.InsertPrivacyPairParams{
77+
GroupID: groupID,
78+
RealVal: real,
79+
PseudoVal: pseudo,
80+
})
81+
}
82+
83+
// PseudoToReal will check the db to see if the given pseudo key exists. If
84+
// it does then the real value is returned, else an error is returned.
85+
//
86+
// NOTE: this is part of the PrivacyMapTx interface.
87+
func (p *privacyMapSQLTx) PseudoToReal(ctx context.Context,
88+
pseudo string) (string, error) {
89+
90+
groupID, err := p.getGroupID(ctx)
91+
if err != nil {
92+
return "", err
93+
}
94+
95+
realVal, err := p.queries.GetRealForPseudo(
96+
ctx, sqlc.GetRealForPseudoParams{
97+
GroupID: groupID,
98+
PseudoVal: pseudo,
99+
},
100+
)
101+
if errors.Is(err, sql.ErrNoRows) {
102+
return "", ErrNoSuchKeyFound
103+
} else if err != nil {
104+
return "", err
105+
}
106+
107+
return realVal, nil
108+
}
109+
110+
// RealToPseudo will check the db to see if the given real key exists. If it
111+
// does then the pseudo value is returned, else an error is returned.
112+
//
113+
// NOTE: this is part of the PrivacyMapTx interface.
114+
func (p *privacyMapSQLTx) RealToPseudo(ctx context.Context,
115+
real string) (string, error) {
116+
117+
groupID, err := p.getGroupID(ctx)
118+
if err != nil {
119+
return "", err
120+
}
121+
122+
pseudo, err := p.queries.GetPseudoForReal(
123+
ctx, sqlc.GetPseudoForRealParams{
124+
GroupID: groupID,
125+
RealVal: real,
126+
},
127+
)
128+
if errors.Is(err, sql.ErrNoRows) {
129+
return "", ErrNoSuchKeyFound
130+
} else if err != nil {
131+
return "", err
132+
}
133+
134+
return pseudo, nil
135+
}
136+
137+
// FetchAllPairs loads and returns the real-to-pseudo pairs.
138+
//
139+
// NOTE: this is part of the PrivacyMapTx interface.
140+
func (p *privacyMapSQLTx) FetchAllPairs(ctx context.Context) (*PrivacyMapPairs,
141+
error) {
142+
143+
groupID, err := p.getGroupID(ctx)
144+
if err != nil {
145+
return nil, err
146+
}
147+
148+
pairs, err := p.queries.GetAllPrivacyPairs(ctx, groupID)
149+
if err != nil {
150+
return nil, err
151+
}
152+
153+
privacyPairs := make(map[string]string, len(pairs))
154+
for _, pair := range pairs {
155+
privacyPairs[pair.RealVal] = pair.PseudoVal
156+
}
157+
158+
return NewPrivacyMapPairs(privacyPairs), nil
159+
}
160+
161+
// getGroupID is a helper that can be used to get the DB ID for a session group
162+
// given the group ID alias. If such a group is not found, then
163+
// session.ErrUnknownGroup is returned.
164+
func (p *privacyMapSQLTx) getGroupID(ctx context.Context) (int64, error) {
165+
groupID, err := p.queries.GetSessionIDByAlias(ctx, p.groupID[:])
166+
if errors.Is(err, sql.ErrNoRows) {
167+
return 0, session.ErrUnknownGroup
168+
} else if err != nil {
169+
return 0, err
170+
}
171+
172+
return groupID, nil
173+
}
174+
175+
// A compile-time constraint to ensure that the privacyMapSQLTx type implements
176+
// the PrivacyMapTx interface.
177+
var _ PrivacyMapTx = (*privacyMapSQLTx)(nil)

firewalldb/privacy_mapper_test.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,13 @@ func TestPrivacyMapStorage(t *testing.T) {
1717
ctx := context.Background()
1818

1919
sessions := session.NewTestDB(t, clock.NewDefaultClock())
20-
db, err := NewBoltDB(t.TempDir(), "test.db", sessions)
21-
require.NoError(t, err)
22-
t.Cleanup(func() {
23-
_ = db.Close()
24-
})
20+
db := NewTestDBWithSessions(t, sessions)
2521

2622
// First up, let's test that the correct error is returned if an
2723
// attempt is made to write to a privacy map that is not linked to
2824
// an existing session group.
2925
pdb := db.PrivacyDB(session.ID{1, 2, 3, 4})
30-
err = pdb.Update(ctx,
26+
err := pdb.Update(ctx,
3127
func(ctx context.Context, tx PrivacyMapTx) error {
3228
_, err := tx.RealToPseudo(ctx, "real")
3329
require.ErrorIs(t, err, session.ErrUnknownGroup)
@@ -54,7 +50,7 @@ func TestPrivacyMapStorage(t *testing.T) {
5450
pdb1 := db.PrivacyDB(sess.GroupID)
5551

5652
_ = pdb1.Update(ctx, func(ctx context.Context, tx PrivacyMapTx) error {
57-
_, err = tx.RealToPseudo(ctx, "real")
53+
_, err := tx.RealToPseudo(ctx, "real")
5854
require.ErrorIs(t, err, ErrNoSuchKeyFound)
5955

6056
_, err = tx.PseudoToReal(ctx, "pseudo")
@@ -89,7 +85,7 @@ func TestPrivacyMapStorage(t *testing.T) {
8985
pdb2 := db.PrivacyDB(sess2.GroupID)
9086

9187
_ = pdb2.Update(ctx, func(ctx context.Context, tx PrivacyMapTx) error {
92-
_, err = tx.RealToPseudo(ctx, "real")
88+
_, err := tx.RealToPseudo(ctx, "real")
9389
require.ErrorIs(t, err, ErrNoSuchKeyFound)
9490

9591
_, err = tx.PseudoToReal(ctx, "pseudo")
@@ -227,11 +223,7 @@ func TestPrivacyMapTxs(t *testing.T) {
227223
ctx := context.Background()
228224

229225
sessions := session.NewTestDB(t, clock.NewDefaultClock())
230-
db, err := NewBoltDB(t.TempDir(), "test.db", sessions)
231-
require.NoError(t, err)
232-
t.Cleanup(func() {
233-
_ = db.Close()
234-
})
226+
db := NewTestDBWithSessions(t, sessions)
235227

236228
sess, err := sessions.NewSession(
237229
ctx, "test", session.TypeAutopilot, time.Unix(1000, 0), "",

firewalldb/sql_store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
// interact with various firewalldb tables.
1212
type SQLQueries interface {
1313
SQLKVStoreQueries
14+
SQLPrivacyPairQueries
1415
}
1516

1617
// BatchedSQLQueries is a version of the SQLQueries that's capable of batched

0 commit comments

Comments
 (0)