-
Notifications
You must be signed in to change notification settings - Fork 45
/
Copy pathmacaroon_recipes.go
132 lines (119 loc) · 4.13 KB
/
macaroon_recipes.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
package lndclient
import (
"context"
"fmt"
"reflect"
"slices"
"strings"
)
var (
// supportedSubservers is a map of all RPC (sub)server names that are
// supported by the lndclient library and their implementing interface
// type. We use reflection to look up the methods implemented on those
// interfaces to find out which permissions are needed for them.
supportedSubservers = map[string]interface{}{
"lnrpc": (*LightningClient)(nil),
"chainrpc": (*ChainNotifierClient)(nil),
"invoicesrpc": (*InvoicesClient)(nil),
"routerrpc": (*RouterClient)(nil),
"signrpc": (*SignerClient)(nil),
"verrpc": (*VersionerClient)(nil),
"walletrpc": (*WalletKitClient)(nil),
}
// renames is a map of renamed RPC method names. The key is the name as
// implemented in lndclient and the value is the original name of the
// RPC method defined in the proto.
renames = map[string]string{
"ChannelBackup": "ExportChannelBackup",
"ChannelBackups": "ExportAllChannelBackups",
"ConfirmedWalletBalance": "WalletBalance",
"Connect": "ConnectPeer",
"DecodePaymentRequest": "DecodePayReq",
"ListTransactions": "GetTransactions",
"PayInvoice": "SendPaymentSync",
"UpdateChanPolicy": "UpdateChannelPolicy",
"NetworkInfo": "GetNetworkInfo",
"SubscribeGraph": "SubscribeChannelGraph",
"InterceptHtlcs": "HtlcInterceptor",
"ImportMissionControl": "XImportMissionControl",
"EstimateFeeRate": "EstimateFee",
"EstimateFeeToP2WSH": "EstimateFee",
"OpenChannelStream": "OpenChannel",
"ListSweepsVerbose": "ListSweeps",
"MinRelayFee": "EstimateFee",
"SignOutputRawKeyLocator": "SignOutputRaw",
}
// ignores is a list of method names on the client implementations that
// we don't need to check macaroon permissions for.
ignores = []string{
"RawClientWithMacAuth",
}
)
// MacaroonRecipe returns a list of macaroon permissions that is required to use
// the full feature set of the given list of RPC package names.
func MacaroonRecipe(c LightningClient, packages []string) ([]MacaroonPermission,
error) {
// Get the full map of RPC URIs and the required permissions from the
// backing lnd instance.
allPermissions, err := c.ListPermissions(context.Background())
if err != nil {
return nil, err
}
uniquePermissions := make(map[string]map[string]struct{})
for _, pkg := range packages {
// Get the typed pointer from our map of supported interfaces.
ifacePtr, ok := supportedSubservers[pkg]
if !ok {
return nil, fmt.Errorf("unknown subserver %s", pkg)
}
// From the pointer type we can find out the interface, its name
// and what methods it declares.
ifaceType := reflect.TypeOf(ifacePtr).Elem()
serverName := strings.ReplaceAll(ifaceType.Name(), "Client", "")
for i := range ifaceType.NumMethod() {
// The methods in lndclient might be called slightly
// differently. Rename according to our rename mapping
// table.
methodName := ifaceType.Method(i).Name
rename, ok := renames[methodName]
if ok {
methodName = rename
}
if slices.Contains(ignores, methodName) {
continue
}
// The full RPC URI is /package.Service/MethodName.
rpcURI := fmt.Sprintf(
"/%s.%s/%s", pkg, serverName, methodName,
)
requiredPermissions, ok := allPermissions[rpcURI]
if !ok {
return nil, fmt.Errorf("URI %s not found in "+
"permission list", rpcURI)
}
// Add these permissions to the map we use to
// de-duplicate the values.
for _, perm := range requiredPermissions {
actions, ok := uniquePermissions[perm.Entity]
if !ok {
actions = make(map[string]struct{})
uniquePermissions[perm.Entity] = actions
}
actions[perm.Action] = struct{}{}
}
}
}
// Turn the de-duplicated map back into a slice of permission entries.
var requiredPermissions []MacaroonPermission
for entity, actions := range uniquePermissions {
for action := range actions {
requiredPermissions = append(
requiredPermissions, MacaroonPermission{
Entity: entity,
Action: action,
},
)
}
}
return requiredPermissions, nil
}