key.go raw

   1  package iamkey
   2  
   3  import (
   4  	"encoding/json"
   5  	"fmt"
   6  	"os"
   7  
   8  	yaml2json "github.com/ghodss/yaml"
   9  	"google.golang.org/protobuf/encoding/protojson"
  10  	"gopkg.in/yaml.v2"
  11  
  12  	"github.com/yandex-cloud/go-genproto/yandex/cloud/iam/v1"
  13  )
  14  
  15  var (
  16  	_ json.Marshaler   = &Key{}
  17  	_ json.Unmarshaler = &Key{}
  18  	_ yaml.Marshaler   = &Key{}
  19  	_ yaml.Unmarshaler = &Key{}
  20  )
  21  
  22  // New creates new Key from IAM Key Service Create response.
  23  func New(created *iam.CreateKeyResponse) *Key {
  24  	if created == nil {
  25  		panic("nil key")
  26  	}
  27  
  28  	public := created.GetKey()
  29  	key := &Key{
  30  		Id:           public.GetId(),
  31  		Subject:      nil,
  32  		CreatedAt:    public.GetCreatedAt(),
  33  		Description:  public.GetDescription(),
  34  		KeyAlgorithm: public.GetKeyAlgorithm(),
  35  		PublicKey:    public.GetPublicKey(),
  36  		PrivateKey:   created.GetPrivateKey(),
  37  	}
  38  
  39  	switch subj := public.GetSubject().(type) {
  40  	case *iam.Key_ServiceAccountId:
  41  		key.Subject = &Key_ServiceAccountId{
  42  			ServiceAccountId: subj.ServiceAccountId,
  43  		}
  44  	case *iam.Key_UserAccountId:
  45  		key.Subject = &Key_UserAccountId{
  46  			UserAccountId: subj.UserAccountId,
  47  		}
  48  	case nil:
  49  		// Do nothing.
  50  	default:
  51  		panic(fmt.Sprintf("unexpected key subject: %#v", subj))
  52  	}
  53  
  54  	return key
  55  }
  56  
  57  // UnmarshalJSON unmarshals IAM Key JSON data.
  58  // Both snake_case (gRPC API) and camelCase (REST API) fields are accepted.
  59  func (m *Key) UnmarshalJSON(data []byte) error {
  60  	return protojson.Unmarshal(data, m)
  61  }
  62  
  63  func (m *Key) MarshalJSON() ([]byte, error) {
  64  	return protojson.MarshalOptions{UseProtoNames: true}.Marshal(m)
  65  }
  66  
  67  // UnmarshalYAML unmarshals IAM Key YAML data.
  68  // Both snake_case (gRPC API) and camelCase (REST API) fields are accepted.
  69  func (m *Key) UnmarshalYAML(unmarshal func(interface{}) error) error {
  70  	var obj yaml.MapSlice
  71  
  72  	err := unmarshal(&obj)
  73  	if err != nil {
  74  		return err
  75  	}
  76  
  77  	yamlData, err := yaml.Marshal(obj)
  78  	if err != nil {
  79  		return err
  80  	}
  81  
  82  	jsonData, err := yaml2json.YAMLToJSON(yamlData)
  83  	if err != nil {
  84  		return err
  85  	}
  86  
  87  	return m.UnmarshalJSON(jsonData)
  88  }
  89  
  90  func (m *Key) MarshalYAML() (interface{}, error) {
  91  	jsonData, err := m.MarshalJSON()
  92  	if err != nil {
  93  		return nil, err
  94  	}
  95  
  96  	var obj yaml.MapSlice
  97  
  98  	err = yaml.Unmarshal(jsonData, &obj)
  99  	if err != nil {
 100  		return nil, err
 101  	}
 102  
 103  	return obj, nil
 104  }
 105  
 106  // ReadFromJSONFile reads IAM Key from JSON bytes.
 107  func ReadFromJSONBytes(keyBytes []byte) (*Key, error) {
 108  	key := &Key{}
 109  
 110  	err := json.Unmarshal(keyBytes, key)
 111  	if err != nil {
 112  		return nil, fmt.Errorf("key unmarshal fail: %w", err)
 113  	}
 114  
 115  	return key, nil
 116  }
 117  
 118  // ReadFromJSONFile reads IAM Key from JSON file.
 119  func ReadFromJSONFile(path string) (*Key, error) {
 120  	data, err := os.ReadFile(path)
 121  	if err != nil {
 122  		return nil, fmt.Errorf("key file '%s' read fail: %w", path, err)
 123  	}
 124  
 125  	return ReadFromJSONBytes(data)
 126  }
 127  
 128  // WriteToJSONFile writes key to file in JSON format.
 129  // File permissions will be 0600, because private key part is sensitive data.
 130  func WriteToJSONFile(path string, key *Key) error {
 131  	data, err := json.MarshalIndent(key, "", "   ")
 132  	if err != nil {
 133  		return fmt.Errorf("key marshal fail: %w", err)
 134  	}
 135  
 136  	err = os.WriteFile(path, data, 0600)
 137  	if err != nil {
 138  		return fmt.Errorf("file '%s' write fail: %w", path, err)
 139  	}
 140  
 141  	return nil
 142  }
 143