code.vegaprotocol.io/vega@v0.79.0/wallet/api/admin_isolate_key_test.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_test 17 18 import ( 19 "context" 20 "fmt" 21 "strings" 22 "testing" 23 24 "code.vegaprotocol.io/vega/libs/jsonrpc" 25 vgrand "code.vegaprotocol.io/vega/libs/rand" 26 "code.vegaprotocol.io/vega/wallet/api" 27 "code.vegaprotocol.io/vega/wallet/api/mocks" 28 29 "github.com/golang/mock/gomock" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 func TestAdminIsolateKey(t *testing.T) { 35 t.Run("Documentation matches the code", testAdminIsolateKeySchemaCorrect) 36 t.Run("Isolating a key with invalid params fails", testIsolatingKeyWithInvalidParamsFails) 37 t.Run("Isolating a key with valid params succeeds", testIsolatingKeyWithValidParamsSucceeds) 38 t.Run("Isolating a key from wallet that does not exists fails", testIsolatingKeyFromWalletThatDoesNotExistsFails) 39 t.Run("Getting internal error during wallet verification fails", testIsolatingKeyGettingInternalErrorDuringWalletVerificationFails) 40 t.Run("Getting internal error during wallet retrieval fails", testIsolatingKeyGettingInternalErrorDuringWalletRetrievalFails) 41 t.Run("Isolating a key that does not exists fails", testIsolatingKeyThatDoesNotExistsFails) 42 t.Run("Getting internal error during isolated wallet saving fails", testIsolatingKeyGettingInternalErrorDuringIsolatedWalletSavingFails) 43 } 44 45 func testAdminIsolateKeySchemaCorrect(t *testing.T) { 46 assertEqualSchema(t, "admin.isolate_key", api.AdminIsolateKeyParams{}, api.AdminIsolateKeyResult{}) 47 } 48 49 func testIsolatingKeyWithInvalidParamsFails(t *testing.T) { 50 tcs := []struct { 51 name string 52 params interface{} 53 expectedError error 54 }{ 55 { 56 name: "with nil params", 57 params: nil, 58 expectedError: api.ErrParamsRequired, 59 }, { 60 name: "with wrong type of params", 61 params: "test", 62 expectedError: api.ErrParamsDoNotMatch, 63 }, { 64 name: "with empty name", 65 params: api.AdminIsolateKeyParams{ 66 Wallet: "", 67 PublicKey: "b5fd9d3c4ad553cb3196303b6e6df7f484cf7f5331a572a45031239fd71ad8a0", 68 IsolatedWalletPassphrase: vgrand.RandomStr(5), 69 }, 70 expectedError: api.ErrWalletIsRequired, 71 }, { 72 name: "with empty isolated passphrase", 73 params: api.AdminIsolateKeyParams{ 74 Wallet: vgrand.RandomStr(5), 75 IsolatedWalletPassphrase: "", 76 PublicKey: "b5fd9d3c4ad553cb3196303b6e6df7f484cf7f5331a572a45031239fd71ad8a0", 77 }, 78 expectedError: api.ErrIsolatedWalletPassphraseIsRequired, 79 }, { 80 name: "with empty public key", 81 params: api.AdminIsolateKeyParams{ 82 Wallet: vgrand.RandomStr(5), 83 PublicKey: "", 84 IsolatedWalletPassphrase: vgrand.RandomStr(5), 85 }, 86 expectedError: api.ErrPublicKeyIsRequired, 87 }, 88 } 89 90 for _, tc := range tcs { 91 t.Run(tc.name, func(tt *testing.T) { 92 // given 93 ctx := context.Background() 94 95 // setup 96 handler := newIsolateKeyHandler(tt) 97 98 // when 99 result, errorDetails := handler.handle(t, ctx, tc.params) 100 101 // then 102 require.Empty(tt, result) 103 assertInvalidParams(tt, errorDetails, tc.expectedError) 104 }) 105 } 106 } 107 108 func testIsolatingKeyWithValidParamsSucceeds(t *testing.T) { 109 // given 110 ctx := context.Background() 111 isolatedPassphrase := vgrand.RandomStr(5) 112 expectedWallet, firstKey := walletWithKey(t) 113 114 // setup 115 handler := newIsolateKeyHandler(t) 116 // -- expected calls 117 handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil) 118 handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil) 119 handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(expectedWallet, nil) 120 handler.walletStore.EXPECT().CreateWallet(ctx, gomock.Any(), isolatedPassphrase).Times(1).Return(nil) 121 122 // when 123 result, errorDetails := handler.handle(t, ctx, api.AdminIsolateKeyParams{ 124 Wallet: expectedWallet.Name(), 125 IsolatedWalletPassphrase: isolatedPassphrase, 126 PublicKey: firstKey.PublicKey(), 127 }) 128 129 // then 130 require.Nil(t, errorDetails) 131 assert.True(t, strings.HasPrefix(result.Wallet, expectedWallet.Name())) 132 } 133 134 func testIsolatingKeyFromWalletThatDoesNotExistsFails(t *testing.T) { 135 // given 136 ctx := context.Background() 137 isolatedPassphrase := vgrand.RandomStr(5) 138 name := vgrand.RandomStr(5) 139 140 // setup 141 handler := newIsolateKeyHandler(t) 142 // -- expected calls 143 handler.walletStore.EXPECT().WalletExists(ctx, name).Times(1).Return(false, nil) 144 145 // when 146 result, errorDetails := handler.handle(t, ctx, api.AdminIsolateKeyParams{ 147 Wallet: name, 148 IsolatedWalletPassphrase: isolatedPassphrase, 149 PublicKey: vgrand.RandomStr(5), 150 }) 151 152 // then 153 require.NotNil(t, errorDetails) 154 assert.Empty(t, result) 155 assertInvalidParams(t, errorDetails, api.ErrWalletDoesNotExist) 156 } 157 158 func testIsolatingKeyGettingInternalErrorDuringWalletVerificationFails(t *testing.T) { 159 // given 160 ctx := context.Background() 161 isolatedPassphrase := vgrand.RandomStr(5) 162 name := vgrand.RandomStr(5) 163 164 // setup 165 handler := newIsolateKeyHandler(t) 166 // -- expected calls 167 handler.walletStore.EXPECT().WalletExists(ctx, name).Times(1).Return(false, assert.AnError) 168 169 // when 170 result, errorDetails := handler.handle(t, ctx, api.AdminIsolateKeyParams{ 171 Wallet: name, 172 IsolatedWalletPassphrase: isolatedPassphrase, 173 PublicKey: vgrand.RandomStr(5), 174 }) 175 176 // then 177 require.NotNil(t, errorDetails) 178 assert.Empty(t, result) 179 assertInternalError(t, errorDetails, fmt.Errorf("could not verify the wallet exists: %w", assert.AnError)) 180 } 181 182 func testIsolatingKeyGettingInternalErrorDuringWalletRetrievalFails(t *testing.T) { 183 // given 184 ctx := context.Background() 185 isolatedPassphrase := vgrand.RandomStr(5) 186 name := vgrand.RandomStr(5) 187 188 // setup 189 handler := newIsolateKeyHandler(t) 190 // -- expected calls 191 handler.walletStore.EXPECT().WalletExists(ctx, name).Times(1).Return(true, nil) 192 handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, name).Times(1).Return(true, nil) 193 handler.walletStore.EXPECT().GetWallet(ctx, name).Times(1).Return(nil, assert.AnError) 194 195 // when 196 result, errorDetails := handler.handle(t, ctx, api.AdminIsolateKeyParams{ 197 Wallet: name, 198 IsolatedWalletPassphrase: isolatedPassphrase, 199 PublicKey: vgrand.RandomStr(5), 200 }) 201 202 // then 203 require.NotNil(t, errorDetails) 204 assert.Empty(t, result) 205 assertInternalError(t, errorDetails, fmt.Errorf("could not retrieve the wallet: %w", assert.AnError)) 206 } 207 208 func testIsolatingKeyGettingInternalErrorDuringIsolatedWalletSavingFails(t *testing.T) { 209 // given 210 ctx := context.Background() 211 isolatedPassphrase := vgrand.RandomStr(5) 212 expectedWallet, firstKey := walletWithKey(t) 213 214 // setup 215 handler := newIsolateKeyHandler(t) 216 // -- expected calls 217 handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil) 218 handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil) 219 handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(expectedWallet, nil) 220 handler.walletStore.EXPECT().CreateWallet(ctx, gomock.Any(), isolatedPassphrase).Times(1).Return(assert.AnError) 221 222 // when 223 result, errorDetails := handler.handle(t, ctx, api.AdminIsolateKeyParams{ 224 Wallet: expectedWallet.Name(), 225 IsolatedWalletPassphrase: isolatedPassphrase, 226 PublicKey: firstKey.PublicKey(), 227 }) 228 229 // then 230 require.NotNil(t, errorDetails) 231 assert.Empty(t, result) 232 assertInternalError(t, errorDetails, fmt.Errorf("could not save the wallet with isolated key: %w", assert.AnError)) 233 } 234 235 func testIsolatingKeyThatDoesNotExistsFails(t *testing.T) { 236 // given 237 ctx := context.Background() 238 isolatedPassphrase := vgrand.RandomStr(5) 239 expectedWallet, _ := walletWithKey(t) 240 241 // setup 242 handler := newIsolateKeyHandler(t) 243 // -- expected calls 244 handler.walletStore.EXPECT().WalletExists(ctx, expectedWallet.Name()).Times(1).Return(true, nil) 245 handler.walletStore.EXPECT().IsWalletAlreadyUnlocked(ctx, expectedWallet.Name()).Times(1).Return(true, nil) 246 handler.walletStore.EXPECT().GetWallet(ctx, expectedWallet.Name()).Times(1).Return(expectedWallet, nil) 247 248 // when 249 result, errorDetails := handler.handle(t, ctx, api.AdminIsolateKeyParams{ 250 Wallet: expectedWallet.Name(), 251 IsolatedWalletPassphrase: isolatedPassphrase, 252 PublicKey: vgrand.RandomStr(5), 253 }) 254 255 // then 256 require.NotNil(t, errorDetails) 257 assert.Empty(t, result) 258 assertInvalidParams(t, errorDetails, api.ErrPublicKeyDoesNotExist) 259 } 260 261 type isolateKeyHandler struct { 262 *api.AdminIsolateKey 263 ctrl *gomock.Controller 264 walletStore *mocks.MockWalletStore 265 } 266 267 func (h *isolateKeyHandler) handle(t *testing.T, ctx context.Context, params jsonrpc.Params) (api.AdminIsolateKeyResult, *jsonrpc.ErrorDetails) { 268 t.Helper() 269 270 rawResult, err := h.Handle(ctx, params) 271 if rawResult != nil { 272 result, ok := rawResult.(api.AdminIsolateKeyResult) 273 if !ok { 274 t.Fatal("AdminIsolateKey handler result is not a AdminIsolateKeyResult") 275 } 276 return result, err 277 } 278 return api.AdminIsolateKeyResult{}, err 279 } 280 281 func newIsolateKeyHandler(t *testing.T) *isolateKeyHandler { 282 t.Helper() 283 284 ctrl := gomock.NewController(t) 285 walletStore := mocks.NewMockWalletStore(ctrl) 286 287 return &isolateKeyHandler{ 288 AdminIsolateKey: api.NewAdminIsolateKey(walletStore), 289 ctrl: ctrl, 290 walletStore: walletStore, 291 } 292 }