@@ -56,9 +56,9 @@ type ImportKeysRequest struct {
5656}
5757
5858type ImportKeyRequest struct {
59- KeyName string
60- Data []byte
61- Password string
59+ NewKeyName string
60+ Data []byte
61+ Password string
6262}
6363
6464type ImportKeysResponse struct {}
@@ -93,10 +93,30 @@ type SetMetadataUpdate struct {
9393type SetMetadataResponse struct {}
9494
9595type Admin interface {
96+ // CreateKeys creates multiple keys in a single atomic operation.
97+ // The response preserves the order of the keys in the request.
98+ // Returns ErrKeyAlreadyExists if any key name already exists,
99+ // ErrInvalidKeyName if any key name is invalid,
100+ // ErrUnsupportedKeyType if any key type is not supported.
96101 CreateKeys (ctx context.Context , req CreateKeysRequest ) (CreateKeysResponse , error )
102+
103+ // DeleteKeys deletes multiple keys in a single atomic operation.
104+ // Returns ErrKeyNotFound if any key does not exist.
97105 DeleteKeys (ctx context.Context , req DeleteKeysRequest ) (DeleteKeysResponse , error )
106+
107+ // ImportKeys imports multiple encrypted keys in a single atomic operation.
108+ // Keys can be renamed during import using NewKeyName.
109+ // Returns ErrKeyAlreadyExists if a key with the target name exists,
110+ // ErrInvalidKeyName if the target name is invalid.
98111 ImportKeys (ctx context.Context , req ImportKeysRequest ) (ImportKeysResponse , error )
112+
113+ // ExportKeys exports multiple keys in encrypted format.
114+ // Each key is encrypted using the parameters specified in the request.
115+ // Returns ErrKeyNotFound if any key does not exist.
99116 ExportKeys (ctx context.Context , req ExportKeysRequest ) (ExportKeysResponse , error )
117+
118+ // SetMetadata updates metadata for multiple keys in a single atomic operation.
119+ // Returns ErrKeyNotFound if any key does not exist.
100120 SetMetadata (ctx context.Context , req SetMetadataRequest ) (SetMetadataResponse , error )
101121}
102122
@@ -237,40 +257,45 @@ func (ks *keystore) ImportKeys(ctx context.Context, req ImportKeysRequest) (Impo
237257 defer ks .mu .Unlock ()
238258
239259 ksCopy := maps .Clone (ks .keystore )
240- for _ , keyReq := range req .Keys {
241- if err := ValidKeyName (keyReq .KeyName ); err != nil {
242- return ImportKeysResponse {}, fmt .Errorf ("%w: %s" , ErrInvalidKeyName , err )
243- }
244- if _ , ok := ksCopy [keyReq .KeyName ]; ok {
245- return ImportKeysResponse {}, fmt .Errorf ("%w: %s" , ErrKeyAlreadyExists , keyReq .KeyName )
246- }
260+ for i , keyReq := range req .Keys {
247261 encData := gethkeystore.CryptoJSON {}
248262 err := json .Unmarshal (keyReq .Data , & encData )
249263 if err != nil {
250- return ImportKeysResponse {}, fmt .Errorf ("key = %s , failed to unmarshal encrypted import data: %w" , keyReq . KeyName , err )
264+ return ImportKeysResponse {}, fmt .Errorf ("key num = %d , failed to unmarshal encrypted import data: %w" , i , err )
251265 }
252266 decData , err := gethkeystore .DecryptDataV3 (encData , keyReq .Password )
253267 if err != nil {
254- return ImportKeysResponse {}, fmt .Errorf ("key = %s , failed to decrypt key: %w" , keyReq . KeyName , err )
268+ return ImportKeysResponse {}, fmt .Errorf ("key num = %d , failed to decrypt key: %w" , i , err )
255269 }
256270 keypb := & serialization.Key {}
257271 err = proto .Unmarshal (decData , keypb )
258272 if err != nil {
259- return ImportKeysResponse {}, fmt .Errorf ("key = %s , failed to unmarshal key: %w" , keyReq . KeyName , err )
273+ return ImportKeysResponse {}, fmt .Errorf ("key num = %d , failed to unmarshal key: %w" , i , err )
260274 }
261275 pkRaw := internal .NewRaw (keypb .PrivateKey )
262276 keyType := KeyType (keypb .KeyType )
263277 publicKey , err := publicKeyFromPrivateKey (pkRaw , keyType )
264278 if err != nil {
265- return ImportKeysResponse {}, fmt .Errorf ("key = %s , failed to get public key from private key: %w" , keyReq . KeyName , err )
279+ return ImportKeysResponse {}, fmt .Errorf ("key num = %d , failed to get public key from private key: %w" , i , err )
266280 }
267281 metadata := keypb .Metadata
268282 // The proto compiler sets empty slices to nil during the serialization (https://github.com/golang/protobuf/issues/1348).
269283 // We set metadata back to empty slice to be consistent with the Create method which initializes it as such.
270284 if metadata == nil {
271285 metadata = []byte {}
272286 }
273- ksCopy [keyReq .KeyName ] = newKey (keyType , pkRaw , publicKey , time .Unix (keypb .CreatedAt , 0 ), metadata )
287+
288+ keyName := keyReq .NewKeyName
289+ if keyName == "" {
290+ keyName = keypb .Name
291+ }
292+ if err := ValidKeyName (keyName ); err != nil {
293+ return ImportKeysResponse {}, fmt .Errorf ("key name = %s, %w: %s" , keyName , ErrInvalidKeyName , err )
294+ }
295+ if _ , ok := ksCopy [keyName ]; ok {
296+ return ImportKeysResponse {}, fmt .Errorf ("key name = %s, %w: %s" , keyName , ErrKeyAlreadyExists , keyName )
297+ }
298+ ksCopy [keyName ] = newKey (keyType , pkRaw , publicKey , time .Unix (keypb .CreatedAt , 0 ), metadata )
274299 }
275300 // Persist it to storage.
276301 if err := ks .save (ctx , ksCopy ); err != nil {
0 commit comments