diff --git a/internal/config/openpgp.go b/internal/config/openpgp.go deleted file mode 100644 index 8da7bff..0000000 --- a/internal/config/openpgp.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( - "crypto/x509" - "crypto/x509/pkix" - "crypto/rsa" - "crypto/rand" - "encoding/pem" - "encoding/json" - "github.com/ProtonMail/go-crypto/openpgp" - "github.com/ProtonMail/go-crypto/openpgp/packet" -) - -type OpenPGP struct { - Armored string - entities openpgp.EntityList -} - -func (o *OpenPGP) Read() (yamlData []byte, err error) { - pemReader := io.NopCloser(strings.NewReader(o.Armored)) - o.entities, err = openpgp.ReadArmoredKeyRing(pemReader) - return -} - - -func (o *OpenPGP) UnmarshalJSON(data []byte) error { - if unmarshalErr := json.Unmarshal(data, o); unmarshalErr != nil { - return unmarshalErr - } - return nil -} - -func (o *OpenPGP) UnmarshalYAML(value *yaml.Node) error { - type decodeOpenPGP OpenPGP - if unmarshalErr := value.Decode((*decodeOpenPGP)(o)); unmarshalErr != nil { - return unmarshalErr - } - return nil -} - -func (o *OpenPGP) Clone() data.Configuration { - jsonGeneric, _ := json.Marshal(c) - clone := NewOpenPGP() - if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil { - panic(unmarshalErr) - } - return clone -} - -func (o *OpenPGP) Type() string { - return "openpgp" -} - -func (o *OpenPGP) 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 *OpenPGP) GetValue(name string) (result any, err error) { - var ok bool - if result, ok = (*c)[name]; !ok { - err = data.ErrUnknownConfigurationKey - } - return -} - - -// Expected key: 0.PrivateKey -func (o *OpenPGP) Has(key string) (ok bool) { - index, field, err := o.GetEntityIndex(key) - if len(o.entities) > index && err == nil { - switch key { - case PublicKey: - ok = o.entities[index].PrimaryKey != nil - case PrivateKey: - ok = o.entities[index].PrimaryKey != nil - } - } - return -} - diff --git a/internal/config/openpgp_test.go b/internal/config/openpgp_test.go deleted file mode 100644 index 2b0cc53..0000000 --- a/internal/config/openpgp_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2024 Matthew Rich . All rights reserved. - -package config - -import ( - "github.com/stretchr/testify/assert" - "testing" - "crypto/x509" -) - -func TestNewOpenPGPConfig(t *testing.T) { - p := NewOpenPGP() - assert.NotNil(t, p) -} - -func TestNewOpenPGPConfigYAML(t *testing.T) { - p := NewOpenPGP() - assert.NotNil(t, p) - - config := ` -openpgp: - publickey: - -` - - yamlErr := c.LoadYAML(config) - assert.Nil(t, yamlErr) - crt, err := c.GetValue("catemplate") - assert.Nil(t, err) - assert.Equal(t, []string{"RKH"}, crt.(*x509.Certificate).Subject.Organization) -} diff --git a/internal/config/openpgpkeyring.go b/internal/config/openpgpkeyring.go new file mode 100644 index 0000000..d07c6f4 --- /dev/null +++ b/internal/config/openpgpkeyring.go @@ -0,0 +1,134 @@ +// 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 +} + diff --git a/internal/config/openpgpkeyring_test.go b/internal/config/openpgpkeyring_test.go new file mode 100644 index 0000000..3ebf646 --- /dev/null +++ b/internal/config/openpgpkeyring_test.go @@ -0,0 +1,131 @@ +// Copyright 2024 Matthew Rich . All rights reserved. + +package config + +import ( + "github.com/stretchr/testify/assert" + "testing" + "fmt" +) + +var ( + privateKey = ` + -----BEGIN PGP PRIVATE KEY BLOCK----- + + xcMGBGhI/VUBCADDVSm3mKY5JsncMMJFV0zELMrmip7dkK3vvMvVWVmMHiC4akDH + WPxUdWNQPjE2e5HGF9Ebg0c7gu634VG470MnTzFdPV6f5zA+yJfdKrLq7gpl9QGW + jFLIeK/l4xc+MIpOE1rD9WqYUUw2IYY8YANYq4yB36rq41VuZps/adI9Go5IhfcU + 3SVb7o7pa/gWE0FVu9ze31j2agC8FIKHgB++7bmYgbAQz5Qi1qgtG0Kn25QUacJ6 + Akm2+h4w3SQCR6HLRV2BO29x9mFBszf2KQ7DW2VNiGyUuQQ3m8v2ZidG/11ff6U6 + ad5tvr/8sYr5jOnKEJyDP9v9yQ04cU94GmsPABEBAAH+CQMIljE6AMIbuXNgXPhS + /aEINY2LCOvNUhTUGcepN5zlRJSqGmHCZJ4sI5TWvOzNM4ZCdjQsYYbZhXz5i+SW + R+YeoJKrI/c3jCsazgCUaBqjdHvTi/rHXT77SEQ2c1wBfXmYUbWPpyKeWu31nSnj + 3vZCLtwoyWtCuR2lWbHtYu6hJu+wTm6chGxiBdCKEOKXCx9ZIiVKYvZE93tSITDX + R47rVUpMIt46m0tOr4CbsLjpsbAo6izviqFCMQblHr8kk31IF6yhAnwIfcGr0y3j + zzlEY5ntyUqBD6Gwth1wAboWSD4nupq7wRh/TJXes++udR2rPR05lg1HYVbmBvSt + 03VGk5WQGhFjixU1LxKir7KMJOnDyMxGShTrx/GIhPpG0srWHLJhQtQ+yP0PrlVk + ho7JrhBNUbf9uCjSPSVCclgk1JrYNEDcwtitBnwR7QU2bkRQU3VhYjiesRcmTeSg + PQttdZoB8aCNfiXlLXb2GnacI49XbH+W4B0HgwqZ4dYSuri37BOm9Gvt9hoZGgsE + fdPt//Oox1N0tkwN+j3aLaOkmJSLlzarVlV3A+j3mkY336WalCRd6HFe3RrEgkVH + 53M2dAdbhNlZAlKOwpsiUGwDFX4AiuWJuqXUpoVt4KTRuoYdVg9B0aXW67WM9eai + T9oyur9hZnRy7QANhzuU6m3FBy2EOWHn3c87axK+o48mGDxDYm9PlhIXGbZ7Vb3g + diCE2SkiPerZ0Cx0yO3egUy8BIWHdNWdyDYtcGiup8A7WOyF8ftUCynQkdldtYWx + 5HFlcpiV3o/5C5lkUMMHF72fNOyWwz3PCpLO1uOn+T+jtylkrEY8061SlBF91HA/ + jaLF6U136VTS1hIj9fjzBhk5a6/43Bk41hhgD0JrVFRFM+S9JIdmwQO1FN41QL1i + xKvQOWOE2s1bzS9UZXN0VXNlcjEgKFRlc3RVc2VyMSkgPHRlc3R1c2VyQHJvc3Nr + ZWVuLmhvdXNlPsLAigQTAQgAPgUCaEj9VQkQ3weSNhbTZdcWIQQAzpwPAGodxV8p + f5vfB5I2FtNl1wIbAwIeAQIZAQILBwIVCAMWAAIDJwcCAABiiwf/cIcIHy5KE2CP + kNE3trmV5exT8ltLeLW1EqCNWolcPspjQ1fsLqmLI2A6G9jMiv0wBZEgqmYQSEWx + i0SbcM0MJBf2phrnpR0kgV9y3cSv7KdlFPs7/zQRD9S5VDSnIbsaXQT2Iyh3Wziz + 6CqhX3Qro0saVkyHigsL5w7bj/j5bI1IHGn8TMfnFcHu+wGdRYuQgQ/Q6+5zbC6L + 8sK0orM8lYeXk9KW3LvBJX+aGEDU9at5rGqq8PebIZRkIsFYK3070Qg3mZymnx8D + FKIePKLbDSPWktB6QoYviTXfjy3v1pbI+cfqtLB3Puf9uM0LzdFsfXzxOP+8/D6/ + glIQMYyO4cfDBgRoSP1VAQgAn2oaIthkcTnzqieGTfE3vuGyXjkHc06HwIrHwlO9 + +qvjLxCrQLmO9r81nREVqZ+1wAZrZHyCPF8smvIhyrhBghE8tGKGdeRiwYEh4S55 + TdlP+AZK1Ixr1I2VqrlttoHxQdavGXUhsKYPIa7KWP2/p5wBnWsKvoXxOmEUE5hu + bZAa3LcX8YJQZys3s5i9Wt2q0x1n9kkZS3gFjSOLAAq8j/+aZQ+vvWfWF0yng5V5 + 4GugcwfNMuxdoNHD3bV9tHVgBseIq6tiNksZQAb1jGa3ZtlKa+sixw9s06W39RZC + hVMPY9Jay9XzKtP4/c2yibE4egrTpRdOLAHqBFfUmd+hrwARAQAB/gkDCAAuxoQ+ + wVtrYFWspVOMEjwr+2KBmNGJhv6lmsR7C8oauG3W2tz5EUbNz40k+hR+Plft5CuD + s5OwMsKJIRcnFOqTqGf9KhF74yDAzOem0cmxR+XKzhBhgcnj2fGoOMQqN4XnAVFG + B39p4JK+9IkkHCDefHdXZ6EOpjpmaPL41EmO/l02WOhgW9x69waSLpNlDK1YI7gH + 72Zhr5BACkv3QWizzU3DP//XQaFyzpjKI01q6f+IXonFkaOiPJXP8Ym4ZAA5FXMF + xZl4V0qpsPyvy1PXx7O6NWG0CqV0LpJwsTf2HFXwnnEniZGB3MZqCq1ORoKHsIQe + Q27iFhqSM0iYHPL/iRt/TRwYgW3NZwpUh/OtiSMRy32BeQ2SMKocHPrqQsZvPYgF + KdZVvpu3n/n8Lj8Wtx+89vz28kd5HG6M01HmE8PDdRp4lryH/pPJb0I/W4TRzQgv + ZrWxP8BZPvLiyOxv+74lvV0gr+0zar8jU9RvhsbN/Nt/PU0dl4794K38Xo/vppAQ + GaGFjlQ3he3Vnb5wNA3hUIaBlOGihd28t6Jf3T+oqmfhYtZ95G7Q/8zvCOVadfUf + 5j4xb3LCQYfXNTwDgbGzivpAkje33nX22r38uJg+yeGb8BskMzZWeZMztkw8ia44 + F94D9dxtSa++6VQ97uKxzTza37876YDr4I6LVKu+JVIj4pp8FLS1ebuZC1HngJCB + RO2Ipx9zLIV9Pf4AqH0JW93WomTBnc927EdIeA7EZlybdif4kiRF4hONUIjMcGbt + PBbQbpDlc+ZWJcz7UtJTn9TyUwE0B7oMogV4sGM89jrtlH+BqOwLM1QvpuDTmn3b + eXZn+lZpHm174kN/VMaztxkvuxsmZRemMiHs7k1mAD7umDphep+h0aCkWj5G9miW + r0ypWrjjoGDFOp53AZuJ1sLAdgQYAQgAKgUCaEj9VQkQ3weSNhbTZdcWIQQAzpwP + AGodxV8pf5vfB5I2FtNl1wIbDAAAXFYH/0B/uqlgqV0PPmI1hCW4Wg9/IcBWU6mJ + qR+G+e7uGKNMSAHV+sHIq7ab6TibuAA0GB9aV2xiLV95YFWfp+yle4JzSTuimZCC + iXu55Ouwac0HtTSXXgdwpJMtnZz8m3tlLppdePGlg+rT/mW3z7mxGRfEcj0eEDHq + Ar9EkI0hNG39X+BPhhZZvPxUeCQ8h8cWyOvxutWGbhX/4kpkAbh5I1CnhCtOl0iN + 19rWt33Wp9/KtaE81NASsTaMU5dJT86iN0OMYnunCvSqPgUcAJUvf+ipiiDY2tRZ + /3ZBzDBasRk1lSkkQxQHmr606hnjSWXQDyWy8AFQtkOpa95ilFAX6tA= + =BAfD + -----END PGP PRIVATE KEY BLOCK----- +` + publicKey = ` + -----BEGIN PGP PUBLIC KEY BLOCK----- + + xsBNBGhI/VUBCADDVSm3mKY5JsncMMJFV0zELMrmip7dkK3vvMvVWVmMHiC4akDH + WPxUdWNQPjE2e5HGF9Ebg0c7gu634VG470MnTzFdPV6f5zA+yJfdKrLq7gpl9QGW + jFLIeK/l4xc+MIpOE1rD9WqYUUw2IYY8YANYq4yB36rq41VuZps/adI9Go5IhfcU + 3SVb7o7pa/gWE0FVu9ze31j2agC8FIKHgB++7bmYgbAQz5Qi1qgtG0Kn25QUacJ6 + Akm2+h4w3SQCR6HLRV2BO29x9mFBszf2KQ7DW2VNiGyUuQQ3m8v2ZidG/11ff6U6 + ad5tvr/8sYr5jOnKEJyDP9v9yQ04cU94GmsPABEBAAHNL1Rlc3RVc2VyMSAoVGVz + dFVzZXIxKSA8dGVzdHVzZXJAcm9zc2tlZW4uaG91c2U+wsCKBBMBCAA+BQJoSP1V + CRDfB5I2FtNl1xYhBADOnA8Aah3FXyl/m98HkjYW02XXAhsDAh4BAhkBAgsHAhUI + AxYAAgMnBwIAAGKLB/9whwgfLkoTYI+Q0Te2uZXl7FPyW0t4tbUSoI1aiVw+ymND + V+wuqYsjYDob2MyK/TAFkSCqZhBIRbGLRJtwzQwkF/amGuelHSSBX3LdxK/sp2UU + +zv/NBEP1LlUNKchuxpdBPYjKHdbOLPoKqFfdCujSxpWTIeKCwvnDtuP+PlsjUgc + afxMx+cVwe77AZ1Fi5CBD9Dr7nNsLovywrSiszyVh5eT0pbcu8Elf5oYQNT1q3ms + aqrw95shlGQiwVgrfTvRCDeZnKafHwMUoh48otsNI9aS0HpChi+JNd+PLe/Wlsj5 + x+q0sHc+5/24zQvN0Wx9fPE4/7z8Pr+CUhAxjI7hzsBNBGhI/VUBCACfahoi2GRx + OfOqJ4ZN8Te+4bJeOQdzTofAisfCU736q+MvEKtAuY72vzWdERWpn7XABmtkfII8 + Xyya8iHKuEGCETy0YoZ15GLBgSHhLnlN2U/4BkrUjGvUjZWquW22gfFB1q8ZdSGw + pg8hrspY/b+nnAGdawq+hfE6YRQTmG5tkBrctxfxglBnKzezmL1a3arTHWf2SRlL + eAWNI4sACryP/5plD6+9Z9YXTKeDlXnga6BzB80y7F2g0cPdtX20dWAGx4irq2I2 + SxlABvWMZrdm2Upr6yLHD2zTpbf1FkKFUw9j0lrL1fMq0/j9zbKJsTh6CtOlF04s + AeoEV9SZ36GvABEBAAHCwHYEGAEIACoFAmhI/VUJEN8HkjYW02XXFiEEAM6cDwBq + HcVfKX+b3weSNhbTZdcCGwwAAFxWB/9Af7qpYKldDz5iNYQluFoPfyHAVlOpiakf + hvnu7hijTEgB1frByKu2m+k4m7gANBgfWldsYi1feWBVn6fspXuCc0k7opmQgol7 + ueTrsGnNB7U0l14HcKSTLZ2c/Jt7ZS6aXXjxpYPq0/5lt8+5sRkXxHI9HhAx6gK/ + RJCNITRt/V/gT4YWWbz8VHgkPIfHFsjr8brVhm4V/+JKZAG4eSNQp4QrTpdIjdfa + 1rd91qffyrWhPNTQErE2jFOXSU/OojdDjGJ7pwr0qj4FHACVL3/oqYog2NrUWf92 + QcwwWrEZNZUpJEMUB5q+tOoZ40ll0A8lsvABULZDqWveYpRQF+rQ + =jBvZ + -----END PGP PUBLIC KEY BLOCK----- +` +) + +func TestNewOpenPGPKeyRingConfig(t *testing.T) { + p := NewOpenPGPKeyRing() + assert.NotNil(t, p) +} + +func TestNewOpenPGPKeyRingConfigYAML(t *testing.T) { + p := NewOpenPGPKeyRing() + assert.NotNil(t, p) + + config := fmt.Sprintf(` +keyring: |- +%s +%s +`, publicKey, privateKey) + + yamlErr := p.LoadYAML(config) + assert.Nil(t, yamlErr) + +/* + crt, err := p.GetValue("catemplate") + assert.Nil(t, err) + assert.Equal(t, []string{"RKH"}, crt.(*x509.Certificate).Subject.Organization) +*/ + +} diff --git a/internal/config/openpgpsignature.go b/internal/config/openpgpsignature.go new file mode 100644 index 0000000..1347263 --- /dev/null +++ b/internal/config/openpgpsignature.go @@ -0,0 +1,135 @@ +// 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 OpenPGPSignature struct { + KeyRing string `json:"keyring,omitempty" yaml:"keyring,omitempty"` + Signature string `json:"signature,omitempty" yaml:"signature,omitempty"` + entities openpgp.EntityList +} + +func NewOpenPGPSignature() *OpenPGPSignature { + o := &OpenPGPSignature{} + return o +} + +func (o *OpenPGPSignature) URI() string { + return fmt.Sprintf("%s://%s", o.Type(), "") +} + +func (o *OpenPGPSignature) SetURI(uri string) error { + return nil +} + +func (o *OpenPGPSignature) SetParsedURI(uri data.URIParser) error { + return nil +} + +func (o *OpenPGPSignature) Read(ctx context.Context) (yamlData []byte, err error) { + pemReader := io.NopCloser(strings.NewReader(o.KeyRing)) + o.entities, err = openpgp.ReadArmoredKeyRing(pemReader) + return +} + +func (o *OpenPGPSignature) Load(r io.Reader) (err error) { + err = codec.NewYAMLDecoder(r).Decode(o) + if err == nil { + _, err = o.Read(context.Background()) + } + return err +} + +func (o *OpenPGPSignature) 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 *OpenPGPSignature) UnmarshalJSON(data []byte) error { + if unmarshalErr := json.Unmarshal(data, o); unmarshalErr != nil { + return unmarshalErr + } + //o.NewReadConfigCommand() + return nil +} + +func (o *OpenPGPSignature) UnmarshalYAML(value *yaml.Node) error { + type decodeOpenPGP OpenPGPSignature + if unmarshalErr := value.Decode((*decodeOpenPGP)(o)); unmarshalErr != nil { + return unmarshalErr + } + return nil +} + +func (o *OpenPGPSignature) Clone() data.Configuration { + jsonGeneric, _ := json.Marshal(o) + clone := NewOpenPGPSignature() + if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil { + panic(unmarshalErr) + } + return clone +} + +func (o *OpenPGPSignature) Type() string { + return "openpgp" +} + +func (o *OpenPGPSignature) 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 *OpenPGPSignature) 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 *OpenPGPSignature) 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 +} + diff --git a/internal/config/openpgpsignature_test.go b/internal/config/openpgpsignature_test.go new file mode 100644 index 0000000..568d2d6 --- /dev/null +++ b/internal/config/openpgpsignature_test.go @@ -0,0 +1,33 @@ +// Copyright 2024 Matthew Rich . All rights reserved. + +package config + +import ( + "context" + "github.com/stretchr/testify/assert" + "testing" + "fmt" +) + +func TestNewOpenPGPSignatureConfig(t *testing.T) { + p := NewOpenPGPSignature() + assert.NotNil(t, p) +} + +func TestNewOpenPGPSignatureConfigYAML(t *testing.T) { + p := NewOpenPGPSignature() + assert.NotNil(t, p) + + + + config := fmt.Sprintf(` +keyring: |- +%s +%s +`, publicKey, privateKey) + + yamlErr := p.LoadYAML(config) + assert.Nil(t, yamlErr) + + p.Read(context.Background()) +} diff --git a/internal/config/schemas/openpgp.schema.json b/internal/config/schemas/openpgp.schema.json new file mode 100644 index 0000000..3195d95 --- /dev/null +++ b/internal/config/schemas/openpgp.schema.json @@ -0,0 +1,9 @@ +{ + "$id": "openpgp.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "openpgp", + "type": "object", + "required": [ "path", "filetype" ], + "properties": { + } +} diff --git a/internal/config/system.go b/internal/config/system.go index be193b0..aa59f8b 100644 --- a/internal/config/system.go +++ b/internal/config/system.go @@ -40,6 +40,7 @@ func NewSystem() *System { s["importpath"] = []string { "/etc/jx/lib", } + s["keyringpath"] = "/etc/jx/pgp/keyring.asc" return &s }