-
Notifications
You must be signed in to change notification settings - Fork 22
/
connected_wallet.go
172 lines (143 loc) · 4.55 KB
/
connected_wallet.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package api
import (
"fmt"
"code.vegaprotocol.io/vega/wallet/wallet"
)
// ConnectedWallet is the projection of the wallet through the permissions
// and authentication system. On a regular wallet, there are no restrictions
// on what we can call, which doesn't fit the model of having allowed
// access, so we wrap the "regular wallet" behind the "connected wallet".
type ConnectedWallet struct {
// name is the name of the wallet.
name string
// Hostname is the hostname for which the connection is set.
hostname string
// allowedKeys holds the keys that have been selected by the client
// during the permissions request.
// The order should match the order of generation in the wallet.
allowedKeys []AllowedKey
// noRestrictions is a hack to know if we should skip permission
// verification when we are connected with a long-living API token.
noRestrictions bool
canListKeys bool
}
func (s *ConnectedWallet) Name() string {
return s.name
}
// Hostname returns the hostname for which the connection has been set.
// For long-living connections, the hostname is empty as there is no
// restrictions for that type of connection.
func (s *ConnectedWallet) Hostname() string {
return s.hostname
}
// AllowedKeys returns the keys a connection has access to. If a third-party
// application tries to use a keys that does not belong to this set, then the
// request should fail.
func (s *ConnectedWallet) AllowedKeys() []AllowedKey {
return s.allowedKeys
}
// RequireInteraction tells if an interaction with the user is needed for
// supervision is required or not.
// It is related to the type of API token that is used for this connection.
// If it's a long-living token, then no interaction is required.
func (s *ConnectedWallet) RequireInteraction() bool {
return !s.noRestrictions
}
func (s *ConnectedWallet) CanListKeys() bool {
if s.noRestrictions {
return true
}
return s.canListKeys
}
// CanUseKey determines if the permissions allow the specified key to be used.
func (s *ConnectedWallet) CanUseKey(publicKeyToUse string) bool {
for _, allowedKey := range s.allowedKeys {
if allowedKey.PublicKey() == publicKeyToUse {
return true
}
}
return false
}
func (s *ConnectedWallet) RefreshFromWallet(freshWallet wallet.Wallet) error {
if s.noRestrictions {
s.allowedKeys = allUsableKeys(freshWallet)
return nil
}
rks, err := allowedKeys(freshWallet, s.hostname)
if err != nil {
return fmt.Errorf("could not resolve the allowed keys when refreshing the connection: %w", err)
}
s.canListKeys = rks != nil
s.allowedKeys = rks
return nil
}
type AllowedKey struct {
publicKey string
name string
}
func (r AllowedKey) PublicKey() string {
return r.publicKey
}
func (r AllowedKey) Name() string {
return r.name
}
func NewConnectedWallet(hostname string, w wallet.Wallet) (ConnectedWallet, error) {
rks, err := allowedKeys(w, hostname)
if err != nil {
return ConnectedWallet{}, fmt.Errorf("could not resolve the allowed keys: %w", err)
}
return ConnectedWallet{
noRestrictions: false,
canListKeys: rks != nil,
allowedKeys: rks,
hostname: hostname,
name: w.Name(),
}, nil
}
func NewLongLivingConnectedWallet(w wallet.Wallet) ConnectedWallet {
return ConnectedWallet{
noRestrictions: true,
canListKeys: true,
allowedKeys: allUsableKeys(w),
hostname: "",
name: w.Name(),
}
}
func allowedKeys(w wallet.Wallet, hostname string) ([]AllowedKey, error) {
perms := w.Permissions(hostname)
if !perms.PublicKeys.Enabled() {
return nil, nil
}
if !perms.PublicKeys.HasAllowedKeys() {
// If there is no allowed keys set for this hostname, we load all valid
// keys.
return allUsableKeys(w), nil
}
allowedKeys := make([]AllowedKey, 0, len(perms.PublicKeys.AllowedKeys))
for _, pubKey := range perms.PublicKeys.AllowedKeys {
keyPair, err := w.DescribeKeyPair(pubKey)
if err != nil {
return nil, fmt.Errorf("could not load the key pair associated to the public key %q: %w", pubKey, err)
}
// There is no need to check for the tainted keys, here, as this list
// should only contain usable keys.
allowedKeys = append(allowedKeys, AllowedKey{
publicKey: keyPair.PublicKey(),
name: keyPair.Name(),
})
}
return allowedKeys, nil
}
func allUsableKeys(w wallet.Wallet) []AllowedKey {
allKeyPairs := w.ListKeyPairs()
allowedKeys := make([]AllowedKey, 0, len(allKeyPairs))
for _, keyPair := range allKeyPairs {
if !keyPair.IsTainted() {
allowedKeys = append(allowedKeys, AllowedKey{
publicKey: keyPair.PublicKey(),
name: keyPair.Name(),
})
}
}
return allowedKeys
}