github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/auth/key/keybook.go (about) 1 package key 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "sync" 8 9 ic "github.com/libp2p/go-libp2p-core/crypto" 10 ) 11 12 // Book defines the interface for keybook implementations 13 // which hold the key information 14 type Book interface { 15 // PubKey stores the public key for a key.ID 16 PubKey(context.Context, ID) ic.PubKey 17 18 // AddPubKey stores the public for a key.ID 19 AddPubKey(context.Context, ID, ic.PubKey) error 20 21 // PrivKey returns the private key for a key.ID, if known 22 PrivKey(context.Context, ID) ic.PrivKey 23 24 // AddPrivKey stores the private key for a key.ID 25 AddPrivKey(context.Context, ID, ic.PrivKey) error 26 27 // IDsWithKeys returns all the key IDs stored in the KeyBook 28 IDsWithKeys(context.Context) []ID 29 } 30 31 type memoryKeyBook struct { 32 sync.RWMutex // same lock. wont happen a ton. 33 pks map[ID]ic.PubKey 34 sks map[ID]ic.PrivKey 35 } 36 37 var _ Book = (*memoryKeyBook)(nil) 38 39 func newKeyBook() *memoryKeyBook { 40 return &memoryKeyBook{ 41 pks: map[ID]ic.PubKey{}, 42 sks: map[ID]ic.PrivKey{}, 43 } 44 } 45 46 // IDsWithKeys returns the list of IDs in the KeyBook 47 func (mkb *memoryKeyBook) IDsWithKeys(_ context.Context) []ID { 48 mkb.RLock() 49 ps := make([]ID, 0, len(mkb.pks)+len(mkb.sks)) 50 for p := range mkb.pks { 51 ps = append(ps, p) 52 } 53 for p := range mkb.sks { 54 if _, found := mkb.pks[p]; !found { 55 ps = append(ps, p) 56 } 57 } 58 mkb.RUnlock() 59 return ps 60 } 61 62 // PubKey returns the public key for a given ID if it exists 63 func (mkb *memoryKeyBook) PubKey(_ context.Context, k ID) ic.PubKey { 64 mkb.RLock() 65 pk := mkb.pks[k] 66 mkb.RUnlock() 67 // TODO(arqu): we ignore the recovery mechanic to avoid magic 68 // behavior in above stores. We should revisit once we work out 69 // the broader mechanics of managing keys. 70 // pk, _ = p.ExtractPublicKey() 71 // if err == nil { 72 // mkb.Lock() 73 // mkb.pks[p] = pk 74 // mkb.Unlock() 75 // } 76 return pk 77 } 78 79 // AddPubKey inserts a public key for a given ID 80 func (mkb *memoryKeyBook) AddPubKey(_ context.Context, k ID, pk ic.PubKey) error { 81 mkb.Lock() 82 mkb.pks[k] = pk 83 mkb.Unlock() 84 return nil 85 } 86 87 // PrivKey returns the private key for a given ID if it exists 88 func (mkb *memoryKeyBook) PrivKey(_ context.Context, k ID) ic.PrivKey { 89 mkb.RLock() 90 sk := mkb.sks[k] 91 mkb.RUnlock() 92 return sk 93 } 94 95 // AddPrivKey inserts a private key for a given ID 96 func (mkb *memoryKeyBook) AddPrivKey(_ context.Context, k ID, sk ic.PrivKey) error { 97 if sk == nil { 98 return errors.New("sk is nil (PrivKey)") 99 } 100 101 mkb.Lock() 102 mkb.sks[k] = sk 103 mkb.Unlock() 104 return nil 105 } 106 107 // MarshalJSON implements the JSON marshal interface 108 func (mkb *memoryKeyBook) MarshalJSON() ([]byte, error) { 109 mkb.RLock() 110 res := map[string]interface{}{} 111 pubKeys := map[string]string{} 112 privKeys := map[string]string{} 113 for k, v := range mkb.pks { 114 byteKey, err := ic.MarshalPublicKey(v) 115 if err != nil { 116 // skip/don't marshal ill formed keys 117 log.Debugf("keybook: failed to marshal key: %q", err.Error()) 118 continue 119 } 120 pubKeys[k.Pretty()] = ic.ConfigEncodeKey(byteKey) 121 } 122 for k, v := range mkb.sks { 123 byteKey, err := ic.MarshalPrivateKey(v) 124 if err != nil { 125 // skip/don't marshal ill formed keys 126 log.Debugf("keybook: failed to marshal key: %q", err.Error()) 127 continue 128 } 129 privKeys[k.Pretty()] = ic.ConfigEncodeKey(byteKey) 130 } 131 132 res["public_keys"] = pubKeys 133 res["private_keys"] = privKeys 134 135 mkb.RUnlock() 136 return json.Marshal(res) 137 } 138 139 // UnmarshalJSON implements the JSON unmarshal interface 140 func (mkb *memoryKeyBook) UnmarshalJSON(data []byte) error { 141 ctx := context.Background() 142 keyBookJSON := map[string]map[string]string{} 143 err := json.Unmarshal(data, &keyBookJSON) 144 if err != nil { 145 return err 146 } 147 if pubKeys, ok := keyBookJSON["public_keys"]; ok { 148 for k, v := range pubKeys { 149 byteKey, err := ic.ConfigDecodeKey(v) 150 if err != nil { 151 return err 152 } 153 key, err := ic.UnmarshalPublicKey(byteKey) 154 if err != nil { 155 return err 156 } 157 id, err := DecodeID(k) 158 if err != nil { 159 return err 160 } 161 err = mkb.AddPubKey(ctx, id, key) 162 if err != nil { 163 return err 164 } 165 } 166 } 167 if privKeys, ok := keyBookJSON["private_keys"]; ok { 168 for k, v := range privKeys { 169 byteKey, err := ic.ConfigDecodeKey(v) 170 if err != nil { 171 return err 172 } 173 key, err := ic.UnmarshalPrivateKey(byteKey) 174 if err != nil { 175 return err 176 } 177 id, err := DecodeID(k) 178 if err != nil { 179 return err 180 } 181 err = mkb.AddPrivKey(ctx, id, key) 182 if err != nil { 183 return err 184 } 185 } 186 } 187 return nil 188 }