github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/keys_test.go (about) 1 /* 2 * Copyright 2018-2022 The NATS Authors 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package cmd 17 18 import ( 19 "fmt" 20 "os" 21 "path/filepath" 22 "testing" 23 24 "github.com/nats-io/nkeys" 25 "github.com/stretchr/testify/require" 26 27 "github.com/nats-io/nsc/v2/cmd/store" 28 ) 29 30 func storeOldCreds(ts *TestStore, operator string, account string, user string, data []byte) error { 31 ks := filepath.Join(ts.Dir, "keys") 32 target := filepath.Join(ks, operator, "accounts", account, "users", fmt.Sprintf("%s.creds", user)) 33 return os.WriteFile(target, []byte(user), 0700) 34 35 } 36 37 func storeOldKey(ts *TestStore, operator string, account string, user string, seed []byte) error { 38 // old key layout was: 39 // <op>/<op>.nk 40 // <op>/accounts/<actname>/<actname>.nk 41 // <op>/accounts/<actname>/users/<un>.creds 42 // <op>/accounts/<actname>/users/<un>.nk 43 // new key layout is: 44 // keys/<op>/<first letter pk>/<second and third letters pk>/<pk>.nk 45 // creds/<op>/<actname>/<un>.creds 46 kp, err := store.ExtractSeed(string(seed)) 47 if err != nil { 48 return err 49 } 50 prefix, err := store.KeyType(kp) 51 if err != nil { 52 return err 53 } 54 ks := filepath.Join(ts.Dir, "keys") 55 var target string 56 switch prefix { 57 case nkeys.PrefixByteOperator: 58 target = filepath.Join(ks, operator, fmt.Sprintf("%s.nk", operator)) 59 case nkeys.PrefixByteAccount: 60 target = filepath.Join(ks, operator, "accounts", account, fmt.Sprintf("%s.nk", account)) 61 case nkeys.PrefixByteUser: 62 target = filepath.Join(ks, operator, "accounts", account, "users", fmt.Sprintf("%s.nk", user)) 63 } 64 65 if err := os.MkdirAll(filepath.Dir(target), 0700); err != nil { 66 return err 67 } 68 69 return os.WriteFile(target, seed, 0700) 70 } 71 72 func Test_HasOldStructure(t *testing.T) { 73 ts := NewEmptyStore(t) 74 defer ts.Done(t) 75 76 ks := filepath.Join(ts.Dir, "keys") 77 old := store.KeyStorePath 78 store.KeyStorePath = ks 79 80 oseed, _, _ := CreateOperatorKey(t) 81 require.NoError(t, storeOldKey(ts, "O", "", "", oseed)) 82 require.FileExists(t, filepath.Join(ks, "O", "O.nk")) 83 84 aseed, _, _ := CreateAccountKey(t) 85 require.NoError(t, storeOldKey(ts, "O", "A", "", aseed)) 86 require.FileExists(t, filepath.Join(ks, "O", "accounts", "A", "A.nk")) 87 88 useed, _, _ := CreateUserKey(t) 89 require.NoError(t, storeOldKey(ts, "O", "A", "U", useed)) 90 require.FileExists(t, filepath.Join(ks, "O", "accounts", "A", "users", "U.nk")) 91 92 err := storeOldCreds(ts, "O", "A", "U", []byte("user")) 93 require.NoError(t, err) 94 95 isOld, err := store.IsOldKeyRing(store.GetKeysDir()) 96 require.NoError(t, err) 97 require.True(t, isOld) 98 store.KeyStorePath = old 99 } 100 101 func Test_MigrateKeys(t *testing.T) { 102 ts := NewEmptyStore(t) 103 defer ts.Done(t) 104 105 ks := filepath.Join(ts.Dir, "keys") 106 oldKs := store.KeyStorePath 107 store.KeyStorePath = ks 108 109 oseed, opk, _ := CreateOperatorKey(t) 110 require.NoError(t, storeOldKey(ts, "O", "", "", oseed)) 111 require.FileExists(t, filepath.Join(ks, "O", "O.nk")) 112 113 aseed, apk, _ := CreateAccountKey(t) 114 require.NoError(t, storeOldKey(ts, "O", "A", "", aseed)) 115 require.FileExists(t, filepath.Join(ks, "O", "accounts", "A", "A.nk")) 116 117 useed, upk, _ := CreateUserKey(t) 118 require.NoError(t, storeOldKey(ts, "O", "A", "U", useed)) 119 require.FileExists(t, filepath.Join(ks, "O", "accounts", "A", "users", "U.nk")) 120 121 err := storeOldCreds(ts, "O", "A", "U", []byte("user")) 122 require.NoError(t, err) 123 124 needsUpdate, err := store.KeysNeedMigration() 125 require.NoError(t, err) 126 require.True(t, needsUpdate) 127 128 old, err := store.Migrate() 129 require.NoError(t, err) 130 require.DirExists(t, old) 131 132 // directory for keystore has a "keys" and "creds" 133 keysDir := filepath.Join(ks, "keys") 134 require.FileExists(t, filepath.Join(keysDir, "O", opk[1:3], fmt.Sprintf("%s.nk", opk))) 135 require.FileExists(t, filepath.Join(keysDir, "A", apk[1:3], fmt.Sprintf("%s.nk", apk))) 136 require.FileExists(t, filepath.Join(keysDir, "U", upk[1:3], fmt.Sprintf("%s.nk", upk))) 137 138 credsDir := filepath.Join(ks, "creds") 139 cf := filepath.Join(credsDir, "O", "A", "U.creds") 140 require.FileExists(t, cf) 141 142 for _, pk := range []string{opk, apk, upk} { 143 kp, err := ts.KeyStore.GetKeyPair(pk) 144 require.NoError(t, err) 145 require.NotNil(t, kp) 146 } 147 store.KeyStorePath = oldKs 148 }