-
Notifications
You must be signed in to change notification settings - Fork 43
/
macaroon_service_test.go
150 lines (124 loc) · 3.86 KB
/
macaroon_service_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package lndclient
import (
"context"
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/stretchr/testify/require"
)
// TestMacaroonServiceMigration tests that a client that was using a macaroon
// service encrypted with an empty passphrase can successfully migrate to
// using a shared key passphrase.
func TestMacaroonServiceMigration(t *testing.T) {
// Create a temporary directory where we can store the macaroon db
// we are about to create.
tempDirPath, err := ioutil.TempDir("", ".testMacaroons")
require.NoError(t, err)
defer os.RemoveAll(tempDirPath)
// The initial config we will use has an empty DB password.
cfg := &MacaroonServiceConfig{
DBPath: tempDirPath,
DBFileName: "macaroons.db",
DBTimeout: defaultDBTimeout,
MacaroonLocation: "testLocation",
MacaroonPath: tempDirPath,
DBPassword: []byte{},
}
// Create a new macaroon service with an empty password.
testService, err := createTestService(cfg)
require.NoError(t, err)
defer func() {
require.NoError(t, testService.stop())
}()
err = testService.CreateUnlock(&cfg.DBPassword)
require.NoError(t, err)
// We generate a new root key. This is required for the call the
// ChangePassword to succeed.
err = testService.GenerateNewRootKey()
require.NoError(t, err)
// Close the test db.
err = testService.stop()
require.NoError(t, err)
// Now we will restart the DB but using the new MacaroonService Start
// function which will attempt to upgrade our db to be encrypted with
// a shared secret with LND if we give an empty DB password.
cfg.EphemeralKey = SharedKeyNUMS
cfg.KeyLocator = SharedKeyLocator
sharedSecret := []byte("shared secret")
cfg.LndClient = &LndServices{Signer: &mockSignerClient{
sharedKey: sharedSecret,
}}
ms, err := NewMacaroonService(cfg)
require.NoError(t, err)
// We now start the service. This will attempt to unlock the db using
// the shared secret with LND. This will initially fail and so
// decryption with an empty passphrase will be attempted. If this
// succeeds, then the db will be re-encrypted with the new shared
// secret.
require.NoError(t, ms.Start())
require.NoError(t, ms.Stop())
// To test that the db has been successfully re-encrypted with the new
// key, we remove the connection to lnd and use the shared secret
// directly as the new DB password.
cfg.EphemeralKey = nil
cfg.KeyLocator = nil
cfg.LndClient = nil
cfg.DBPassword = sharedSecret
ms, err = NewMacaroonService(cfg)
require.NoError(t, err)
require.NoError(t, ms.Start())
require.NoError(t, ms.Stop())
}
type testMacaroonService struct {
*macaroons.Service
db kvdb.Backend
}
func createTestService(cfg *MacaroonServiceConfig) (*testMacaroonService,
error) {
db, err := kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
DBPath: cfg.DBPath,
DBFileName: cfg.DBFileName,
DBTimeout: cfg.DBTimeout,
})
if err != nil {
return nil, fmt.Errorf("unable to load macaroon db: "+
"%v", err)
}
// Create the macaroon authentication/authorization service.
service, err := macaroons.NewService(
db, cfg.MacaroonLocation, cfg.StatelessInit, cfg.Checkers...,
)
if err != nil {
return nil, fmt.Errorf("unable to set up macaroon "+
"service: %v", err)
}
return &testMacaroonService{
Service: service,
db: db,
}, nil
}
func (s *testMacaroonService) stop() error {
var returnErr error
if err := s.db.Close(); err != nil {
returnErr = err
}
if err := s.Close(); err != nil {
returnErr = err
}
return returnErr
}
type mockSignerClient struct {
sharedKey []byte
SignerClient
}
func (m *mockSignerClient) DeriveSharedKey(_ context.Context,
_ *btcec.PublicKey, _ *keychain.KeyLocator) ([32]byte, error) {
var res [32]byte
copy(res[:], m.sharedKey)
return res, nil
}