// Copyright 2024 Matthew Rich . All rights reserved. package resource import ( "context" _ "encoding/json" "fmt" "github.com/stretchr/testify/assert" _ "gopkg.in/yaml.v3" "io" _ "log" _ "os" "decl/internal/transport" "decl/internal/ext" "decl/internal/codec" "decl/internal/data" "decl/internal/folio" "strings" "testing" "path/filepath" ) type TestResourceMapper func(key string) (data.Declaration, bool) func (rm TestResourceMapper) Get(key string) (data.Declaration, bool) { return rm(key) } func (rm TestResourceMapper) Has(key string) (ok bool) { _, ok = rm(key) return } func (rm TestResourceMapper) Set(key string, value data.Declaration) { } func (rm TestResourceMapper) Delete(key string) { } type StringContentReadWriter func() (any, error) func (s StringContentReadWriter) ContentWriterStream() (*transport.Writer, error) { w, e := s() return w.(*transport.Writer), e } func (s StringContentReadWriter) ContentReaderStream() (*transport.Reader, error) { r, e := s() return r.(*transport.Reader), e } func (s StringContentReadWriter) Apply(string) error { return nil } func (s StringContentReadWriter) Clone() data.Declaration { return nil } func (s StringContentReadWriter) Load(docData []byte, f codec.Format) (err error) { return } func (s StringContentReadWriter) LoadReader(r io.ReadCloser, f codec.Format) (err error) { return } func (s StringContentReadWriter) LoadString(docData string, f codec.Format) (err error) { return } func (s StringContentReadWriter) LoadDecl(yamlResourceDeclaration string) error { return nil } func (s StringContentReadWriter) ResolveId(ctx context.Context) (string) { return "" } func (s StringContentReadWriter) SetURI(uri string) (error) { return nil } func (s StringContentReadWriter) SetParsedURI(uri data.URIParser) (error) { return nil } func (s StringContentReadWriter) URI() (string) { return "" } func (s StringContentReadWriter) Validate() (error) { return nil } func (s StringContentReadWriter) ResourceType() data.TypeName { return "" } func (s StringContentReadWriter) Resource() data.Resource { return nil } func TestNewPKIKeysResource(t *testing.T) { r := NewPKI() assert.NotNil(t, r) } func TestPKIPrivateKey(t *testing.T) { r := NewPKI() assert.NotNil(t, r) assert.Equal(t, 2048, r.Bits) assert.Nil(t, r.GenerateKey()) assert.NotNil(t, r.privateKey) r.PublicKey() assert.NotNil(t, r.publicKey) } func TestPKIEncodeKeys(t *testing.T) { var privateTarget, publicTarget, certTarget strings.Builder r := NewPKI() assert.NotNil(t, r) assert.Equal(t, 2048, r.Bits) assert.Nil(t, r.GenerateKey()) assert.NotNil(t, r.privateKey) r.PublicKey() assert.NotNil(t, r.publicKey) r.Resources = TestResourceMapper(func(key string) (data.Declaration, bool) { switch key { case "buffer://privatekey": return StringContentReadWriter(func() (any, error) { w := &transport.Writer{} w.SetStream(ext.WriteNopCloser(&privateTarget)) return w, nil }), true case "buffer://publickey": return StringContentReadWriter(func() (any, error) { w := &transport.Writer{} w.SetStream(ext.WriteNopCloser(&publicTarget)) return w, nil }), true case "buffer://certificate": return StringContentReadWriter(func() (any, error) { w := &transport.Writer{} w.SetStream(ext.WriteNopCloser(&certTarget)) return w, nil }), true } return nil, false }) r.PrivateKeyRef = folio.ResourceReference("buffer://privatekey") r.PublicKeyRef = folio.ResourceReference("buffer://publickey") r.Encode() assert.Equal(t, "-----BEGIN RSA PRIVATE KEY-----", strings.Split(privateTarget.String(), "\n")[0]) assert.Equal(t, "-----BEGIN RSA PUBLIC KEY-----", strings.Split(publicTarget.String(), "\n")[0]) r.CertificateRef = folio.ResourceReference("buffer://certificate") e := r.GenerateCertificate() assert.Nil(t, e) assert.Equal(t, "-----BEGIN CERTIFICATE-----", strings.Split(certTarget.String(), "\n")[0]) } func TestPKIResource(t *testing.T) { privateKeyFile, _ := filepath.Abs(TempDir.FilePath("fooprivatekey.pem")) publicKeyFile, _ := filepath.Abs(TempDir.FilePath("foopublickey.pem")) certFile, _ := filepath.Abs(TempDir.FilePath("foocert.pem")) var resourceYaml, readResourceYaml strings.Builder expected := fmt.Sprintf(` privatekeyref: "file://%s" publickeyref: "file://%s" certificateref: "file://%s" bits: 2048 type: pem `, privateKeyFile, publicKeyFile, certFile) r := NewPKI() assert.NotNil(t, r) assert.Equal(t, 2048, r.Bits) assert.Nil(t, r.GenerateKey()) assert.NotNil(t, r.privateKey) r.PublicKey() assert.NotNil(t, r.publicKey) r.PrivateKeyRef = folio.ResourceReference(fmt.Sprintf("file://%s", privateKeyFile)) r.PublicKeyRef = folio.ResourceReference(fmt.Sprintf("file://%s", publicKeyFile)) r.CertificateRef = folio.ResourceReference(fmt.Sprintf("file://%s", certFile)) createErr := r.Create(context.Background()) assert.Nil(t, createErr) assert.FileExists(t, privateKeyFile) assert.FileExists(t, publicKeyFile) assert.FileExists(t, certFile) serializeErr := codec.FormatYaml.Serialize(r, &resourceYaml) assert.Nil(t, serializeErr) assert.YAMLEq(t, expected, resourceYaml.String()) read := NewPKI() assert.NotNil(t, read) read.PrivateKeyRef = folio.ResourceReference(fmt.Sprintf("file://%s", privateKeyFile)) read.PublicKeyRef = folio.ResourceReference(fmt.Sprintf("file://%s", publicKeyFile)) read.CertificateRef = folio.ResourceReference(fmt.Sprintf("file://%s", certFile)) _, readErr := read.Read(context.Background()) assert.Nil(t, readErr) expectedContent := fmt.Sprintf(` privatekey: | %s publickey: | %s certificate: | %s privatekeyref: "file://%s" publickeyref: "file://%s" certificateref: "file://%s" bits: 2048 type: pem `, strings.Replace(read.PrivateKeyPem, "\n", "\n ", -1), strings.Replace(read.PublicKeyPem, "\n", "\n ", -1), strings.Replace(read.CertificatePem, "\n", "\n ", -1), privateKeyFile, publicKeyFile, certFile) readSerializeErr := codec.FormatYaml.Serialize(read, &readResourceYaml) assert.Nil(t, readSerializeErr) assert.YAMLEq(t, expectedContent, readResourceYaml.String()) }