Skip to content

Commit ed31a0a

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 fd7255d commit ed31a0a

File tree

3 files changed

+185
-13
lines changed

3 files changed

+185
-13
lines changed

firewalldb/privacy_mapper_sql.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
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+
Real: 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+
Pseudo: 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+
Real: real,
79+
Pseudo: 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+
Pseudo: 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+
Real: 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.queries.GetSessionIDByAlias(ctx, p.groupID[:])
144+
if errors.Is(err, sql.ErrNoRows) {
145+
return nil, session.ErrUnknownGroup
146+
} else if err != nil {
147+
return nil, err
148+
}
149+
150+
pairs, err := p.queries.GetAllPrivacyPairs(ctx, groupID)
151+
if err != nil {
152+
return nil, err
153+
}
154+
155+
privacyPairs := make(map[string]string, len(pairs))
156+
for _, pair := range pairs {
157+
privacyPairs[pair.Real] = pair.Pseudo
158+
}
159+
160+
return NewPrivacyMapPairs(privacyPairs), nil
161+
}
162+
163+
// getGroupID is a helper that can be used to get the DB ID for a session group
164+
// given the group ID alias. If such a group is not found, then
165+
// session.ErrUnknownGroup is returned.
166+
func (p *privacyMapSQLTx) getGroupID(ctx context.Context) (int64, error) {
167+
groupID, err := p.queries.GetSessionIDByAlias(ctx, p.groupID[:])
168+
if errors.Is(err, sql.ErrNoRows) {
169+
return 0, session.ErrUnknownGroup
170+
} else if err != nil {
171+
return 0, err
172+
}
173+
174+
return groupID, nil
175+
}
176+
177+
// A compile-time constraint to ensure that the privacyMapSQLTx type implements
178+
// the PrivacyMapTx interface.
179+
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)