-
Notifications
You must be signed in to change notification settings - Fork 43
/
macaroon_pouch.go
135 lines (115 loc) · 4.1 KB
/
macaroon_pouch.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
package lndclient
import (
"context"
"encoding/hex"
"os"
"path/filepath"
"google.golang.org/grpc/metadata"
)
// LnrpcServiceMac is the name of a macaroon that can be used to authenticate
// with a specific lnrpc service.
type LnrpcServiceMac string
const (
AdminServiceMac LnrpcServiceMac = "admin.macaroon"
InvoiceServiceMac LnrpcServiceMac = "invoices.macaroon"
ChainNotifierServiceMac LnrpcServiceMac = "chainnotifier.macaroon"
WalletKitServiceMac LnrpcServiceMac = "walletkit.macaroon"
RouterServiceMac LnrpcServiceMac = "router.macaroon"
SignerServiceMac LnrpcServiceMac = "signer.macaroon"
ReadOnlyServiceMac LnrpcServiceMac = "readonly.macaroon"
)
var (
// macaroonServices is the default list of macaroon file names
// that lndclient will attempt to load if a macaroon directory is given
// instead of a single custom macaroon.
macaroonServices = []LnrpcServiceMac{
InvoiceServiceMac,
ChainNotifierServiceMac,
SignerServiceMac,
WalletKitServiceMac,
RouterServiceMac,
AdminServiceMac,
ReadOnlyServiceMac,
}
)
// loadMacaroon tries to load a macaroon file either from the default macaroon
// dir and the default filename or, if specified, from the custom macaroon path
// that overwrites the former two parameters.
func loadMacaroon(defaultMacDir, defaultMacFileName,
customMacPath string) (serializedMacaroon, error) {
// If a custom macaroon path is set, we ignore the macaroon dir and
// default filename and always just load the custom macaroon, assuming
// it contains all permissions needed to use the subservers.
if customMacPath != "" {
return newSerializedMacaroon(customMacPath)
}
return newSerializedMacaroon(filepath.Join(
defaultMacDir, defaultMacFileName,
))
}
// serializedMacaroon is a type that represents a hex-encoded macaroon. We'll
// use this primarily vs the raw binary format as the gRPC metadata feature
// requires that all keys and values be strings.
type serializedMacaroon string
// newSerializedMacaroon reads a new serializedMacaroon from that target
// macaroon path. If the file can't be found, then an error is returned.
func newSerializedMacaroon(macaroonPath string) (serializedMacaroon, error) {
macBytes, err := os.ReadFile(macaroonPath)
if err != nil {
return "", err
}
return serializedMacaroon(hex.EncodeToString(macBytes)), nil
}
// WithMacaroonAuth modifies the passed context to include the macaroon KV
// metadata of the target macaroon. This method can be used to add the macaroon
// at call time, rather than when the connection to the gRPC server is created.
func (s serializedMacaroon) WithMacaroonAuth(ctx context.Context) context.Context {
return metadata.AppendToOutgoingContext(ctx, "macaroon", string(s))
}
// macaroonPouch holds the set of macaroons we need to interact with lnd for
// Loop. Each sub-server has its own macaroon, and for the remaining temporary
// calls that directly hit lnd, we'll use the admin macaroon.
type macaroonPouch map[LnrpcServiceMac]serializedMacaroon
// newMacaroonPouch returns a new instance of a fully populated macaroonPouch
// given the directory where all the macaroons are stored.
func newMacaroonPouch(macaroonDir, customMacPath, customMacHex string) (macaroonPouch,
error) {
// If a custom macaroon is specified, we assume it contains all
// permissions needed for the different subservers to function and we
// use it for all of them.
var (
mac serializedMacaroon
err error
)
if customMacPath != "" {
mac, err = loadMacaroon("", "", customMacPath)
if err != nil {
return nil, err
}
} else if customMacHex != "" {
mac = serializedMacaroon(customMacHex)
}
if mac != "" {
return macaroonPouch{
InvoiceServiceMac: mac,
ChainNotifierServiceMac: mac,
SignerServiceMac: mac,
WalletKitServiceMac: mac,
RouterServiceMac: mac,
AdminServiceMac: mac,
ReadOnlyServiceMac: mac,
}, nil
}
var (
m = make(macaroonPouch)
)
for _, macName := range macaroonServices {
m[macName], err = loadMacaroon(
macaroonDir, string(macName), customMacPath,
)
if err != nil {
return nil, err
}
}
return m, nil
}