-
Notifications
You must be signed in to change notification settings - Fork 43
/
macaroon_recipes.go
119 lines (108 loc) · 3.79 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
package lndclient
import (
"context"
"fmt"
"reflect"
"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",
}
)
// 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 := 0; i < ifaceType.NumMethod(); i++ {
// 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
}
// 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
}