github.com/ethersphere/bee/v2@v2.2.0/pkg/keystore/file/service.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package file
     6  
     7  import (
     8  	"crypto/ecdsa"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	"github.com/ethersphere/bee/v2/pkg/keystore"
    14  )
    15  
    16  // Service is the file-based keystore.Service implementation.
    17  //
    18  // Keys are stored in directory where each private key is stored in a file,
    19  // which is encrypted with symmetric key using some password.
    20  type Service struct {
    21  	dir string
    22  }
    23  
    24  // New creates new file-based keystore.Service implementation.
    25  func New(dir string) *Service {
    26  	return &Service{dir: dir}
    27  }
    28  
    29  func (s *Service) Exists(name string) (bool, error) {
    30  	filename := s.keyFilename(name)
    31  
    32  	data, err := os.ReadFile(filename)
    33  	if err != nil && !os.IsNotExist(err) {
    34  		return false, fmt.Errorf("read private key: %w", err)
    35  	}
    36  	if len(data) == 0 {
    37  		return false, nil
    38  	}
    39  
    40  	return true, nil
    41  }
    42  
    43  func (s *Service) SetKey(name, password string, edg keystore.EDG) (*ecdsa.PrivateKey, error) {
    44  	pk, err := edg.Generate()
    45  	if err != nil {
    46  		return nil, fmt.Errorf("generate key: %w", err)
    47  	}
    48  
    49  	d, err := encryptKey(pk, password, edg)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	filename := s.keyFilename(name)
    55  
    56  	if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	if err := os.WriteFile(filename, d, 0600); err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	return pk, nil
    65  }
    66  
    67  func (s *Service) Key(name, password string, edg keystore.EDG) (pk *ecdsa.PrivateKey, created bool, err error) {
    68  	filename := s.keyFilename(name)
    69  
    70  	data, err := os.ReadFile(filename)
    71  	if err != nil && !os.IsNotExist(err) {
    72  		return nil, false, fmt.Errorf("read private key: %w", err)
    73  	}
    74  	if len(data) == 0 {
    75  		pk, err := s.SetKey(name, password, edg)
    76  		return pk, true, err
    77  	}
    78  
    79  	pk, err = decryptKey(data, password, edg)
    80  	if err != nil {
    81  		return nil, false, err
    82  	}
    83  	return pk, false, nil
    84  }
    85  
    86  func (s *Service) keyFilename(name string) string {
    87  	return filepath.Join(s.dir, fmt.Sprintf("%s.key", name))
    88  }