code.vegaprotocol.io/vega@v0.79.0/wallet/api/client_list_keys.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package api 17 18 import ( 19 "context" 20 "errors" 21 "fmt" 22 23 "code.vegaprotocol.io/vega/libs/jsonrpc" 24 "code.vegaprotocol.io/vega/wallet/wallet" 25 ) 26 27 const PermissionsSuccessfullyUpdated = "The permissions have been successfully updated." 28 29 type ClientListKeysResult struct { 30 Keys []ClientNamedPublicKey `json:"keys"` 31 } 32 33 type ClientNamedPublicKey struct { 34 Name string `json:"name"` 35 PublicKey string `json:"publicKey"` 36 } 37 38 type ClientListKeys struct { 39 walletStore WalletStore 40 interactor Interactor 41 } 42 43 // Handle returns the public keys the third-party application has access to. 44 // 45 // This requires a "read" access on "public_keys". 46 func (h *ClientListKeys) Handle(ctx context.Context, connectedWallet ConnectedWallet) (jsonrpc.Result, *jsonrpc.ErrorDetails) { 47 traceID := jsonrpc.TraceIDFromContext(ctx) 48 49 if !connectedWallet.CanListKeys() { 50 if err := h.updatePublicKeysPermissions(ctx, traceID, &connectedWallet); err != nil { 51 return nil, err 52 } 53 } 54 55 allowedKeys := connectedWallet.AllowedKeys() 56 57 keys := make([]ClientNamedPublicKey, 0, len(allowedKeys)) 58 for _, allowedKey := range allowedKeys { 59 keys = append(keys, ClientNamedPublicKey{ 60 Name: allowedKey.Name(), 61 PublicKey: allowedKey.PublicKey(), 62 }) 63 } 64 65 return ClientListKeysResult{ 66 Keys: keys, 67 }, nil 68 } 69 70 func (h *ClientListKeys) updatePublicKeysPermissions(ctx context.Context, traceID string, connectedWallet *ConnectedWallet) *jsonrpc.ErrorDetails { 71 if err := h.interactor.NotifyInteractionSessionBegan(ctx, traceID, PermissionRequestWorkflow, 2); err != nil { 72 return RequestNotPermittedError(err) 73 } 74 defer h.interactor.NotifyInteractionSessionEnded(ctx, traceID) 75 76 freshWallet, err := h.walletStore.GetWallet(ctx, connectedWallet.Name()) 77 if err != nil { 78 if errors.Is(err, ErrWalletIsLocked) { 79 h.interactor.NotifyError(ctx, traceID, ApplicationErrorType, err) 80 } else { 81 h.interactor.NotifyError(ctx, traceID, InternalErrorType, fmt.Errorf("could not retrieve the wallet for the permissions update: %w", err)) 82 } 83 return InternalError(ErrCouldNotListKeys) 84 } 85 86 perms := freshWallet.Permissions(connectedWallet.Hostname()) 87 88 // At this point, we need a "read" access on public keys. 89 perms.PublicKeys.Access = wallet.ReadAccess 90 approved, err := h.interactor.RequestPermissionsReview(ctx, traceID, 1, connectedWallet.Hostname(), connectedWallet.Name(), perms.Summary()) 91 if err != nil { 92 if errDetails := HandleRequestFlowError(ctx, traceID, h.interactor, err); errDetails != nil { 93 return errDetails 94 } 95 h.interactor.NotifyError(ctx, traceID, InternalErrorType, fmt.Errorf("requesting the permissions review failed: %w", err)) 96 return InternalError(ErrCouldNotListKeys) 97 } 98 if !approved { 99 return UserRejectionError(ErrUserRejectedAccessToKeys) 100 } 101 102 if err := freshWallet.UpdatePermissions(connectedWallet.Hostname(), perms); err != nil { 103 h.interactor.NotifyError(ctx, traceID, InternalErrorType, fmt.Errorf("could not update the permissions on the wallet: %w", err)) 104 return InternalError(ErrCouldNotListKeys) 105 } 106 107 if err := connectedWallet.RefreshFromWallet(freshWallet); err != nil { 108 h.interactor.NotifyError(ctx, traceID, InternalErrorType, fmt.Errorf("could not refresh the connection information after the permissions update: %w", err)) 109 return InternalError(ErrCouldNotListKeys) 110 } 111 112 if err := h.walletStore.UpdateWallet(ctx, freshWallet); err != nil { 113 h.interactor.NotifyError(ctx, traceID, InternalErrorType, fmt.Errorf("could not save the permissions update on the wallet: %w", err)) 114 return InternalError(ErrCouldNotListKeys) 115 } 116 117 h.interactor.NotifySuccessfulRequest(ctx, traceID, 2, PermissionsSuccessfullyUpdated) 118 119 return nil 120 } 121 122 func NewListKeys(walletStore WalletStore, interactor Interactor) *ClientListKeys { 123 return &ClientListKeys{ 124 walletStore: walletStore, 125 interactor: interactor, 126 } 127 }