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