// Copyright 2024 Matthew Rich . All rights reserved. package config import ( "context" "encoding/json" "github.com/ProtonMail/go-crypto/openpgp" "io" "strings" "strconv" "gopkg.in/yaml.v3" "decl/internal/data" "decl/internal/codec" "fmt" "log/slog" ) type OpenPGPKeyRing struct { Keyring string `json:"keyring,omitempty" yaml:"keyring,omitempty"` entities openpgp.EntityList } func NewOpenPGPKeyRing() *OpenPGPKeyRing { o := &OpenPGPKeyRing{} return o } func (o *OpenPGPKeyRing) URI() string { return fmt.Sprintf("%s://%s", o.Type(), "") } func (o *OpenPGPKeyRing) SetURI(uri string) error { return nil } func (o *OpenPGPKeyRing) SetParsedURI(uri data.URIParser) error { return nil } func (o *OpenPGPKeyRing) Read(ctx context.Context) (yamlData []byte, err error) { pemReader := io.NopCloser(strings.NewReader(o.Keyring)) o.entities, err = openpgp.ReadArmoredKeyRing(pemReader) return } func (o *OpenPGPKeyRing) Load(r io.Reader) (err error) { err = codec.NewYAMLDecoder(r).Decode(o) if err == nil { _, err = o.Read(context.Background()) } return err } func (o *OpenPGPKeyRing) LoadYAML(yamlData string) (err error) { err = codec.NewYAMLStringDecoder(yamlData).Decode(o) slog.Info("OpenPGP.LoadYAML()", "keyring", len(o.Keyring), "err", err) if err == nil { _, err = o.Read(context.Background()) } return err } func (o *OpenPGPKeyRing) UnmarshalJSON(data []byte) error { if unmarshalErr := json.Unmarshal(data, o); unmarshalErr != nil { return unmarshalErr } //o.NewReadConfigCommand() return nil } func (o *OpenPGPKeyRing) UnmarshalYAML(value *yaml.Node) error { type decodeOpenPGP OpenPGPKeyRing if unmarshalErr := value.Decode((*decodeOpenPGP)(o)); unmarshalErr != nil { return unmarshalErr } return nil } func (o *OpenPGPKeyRing) Clone() data.Configuration { jsonGeneric, _ := json.Marshal(o) clone := NewOpenPGPKeyRing() if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil { panic(unmarshalErr) } return clone } func (o *OpenPGPKeyRing) Type() string { return "openpgp" } func (o *OpenPGPKeyRing) GetEntityIndex(key string) (index int, field string, err error) { values := strings.SplitN(key, ".", 2) if len(values) == 2 { if index, err = strconv.Atoi(values[0]); err == nil { field = values[1] } } else { err = data.ErrUnknownConfigurationKey } return } func (o *OpenPGPKeyRing) GetValue(name string) (result any, err error) { index, field, err := o.GetEntityIndex(name) if len(o.entities) > index && err == nil { switch field { case "PublicKey": return o.entities[index].PrimaryKey, err case "PrivateKey": return o.entities[index].PrimaryKey, err } } err = data.ErrUnknownConfigurationKey return } // Expected key: 0.PrivateKey func (o *OpenPGPKeyRing) Has(key string) (ok bool) { index, field, err := o.GetEntityIndex(key) if len(o.entities) > index && err == nil { switch field { case "PublicKey": ok = o.entities[index].PrimaryKey != nil case "PrivateKey": ok = o.entities[index].PrimaryKey != nil } } return }