From c5a8512cb6b084128dd92dab7f613229771a9acb Mon Sep 17 00:00:00 2001 From: Jim Ma Date: Mon, 29 Aug 2022 13:59:56 +0800 Subject: [PATCH] feat: add common serialize package (#1601) Signed-off-by: Jim Ma --- client/config/peerhost.go | 74 ++++++---------------------------- client/config/peerhost_test.go | 7 ++-- cmd/dependency/dependency.go | 3 +- manager/config/config.go | 5 ++- manager/manager.go | 2 +- pkg/serialize/pemcontent.go | 74 ++++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 68 deletions(-) create mode 100644 pkg/serialize/pemcontent.go diff --git a/client/config/peerhost.go b/client/config/peerhost.go index 0b4b970e9..1c2176346 100644 --- a/client/config/peerhost.go +++ b/client/config/peerhost.go @@ -28,7 +28,6 @@ import ( "os" "path/filepath" "regexp" - "strings" "time" "gopkg.in/yaml.v3" @@ -40,6 +39,7 @@ import ( logger "d7y.io/dragonfly/v2/internal/dflog" "d7y.io/dragonfly/v2/pkg/dfnet" netip "d7y.io/dragonfly/v2/pkg/net/ip" + "d7y.io/dragonfly/v2/pkg/serialize" "d7y.io/dragonfly/v2/pkg/unit" ) @@ -174,9 +174,9 @@ func ConvertPattern(p string, defaultPattern commonv1.Pattern) commonv1.Pattern } type GlobalSecurityOption struct { - AutoIssueCert bool `mapstructure:"autoIssueCert" yaml:"autoIssueCert"` - CACert PEMContent `mapstructure:"caCert" yaml:"caCert"` - TLSVerify bool `mapstructure:"tlsVerify" yaml:"tlsVerify"` + AutoIssueCert bool `mapstructure:"autoIssueCert" yaml:"autoIssueCert"` + CACert serialize.PEMContent `mapstructure:"caCert" yaml:"caCert"` + TLSVerify bool `mapstructure:"tlsVerify" yaml:"tlsVerify"` } type SchedulerOption struct { @@ -527,12 +527,12 @@ type UnixListenOption struct { type SecurityOption struct { // Insecure indicate enable tls or not - Insecure bool `mapstructure:"insecure" yaml:"insecure"` - CACert PEMContent `mapstructure:"caCert" yaml:"caCert"` - Cert PEMContent `mapstructure:"cert" yaml:"cert"` - Key PEMContent `mapstructure:"key" yaml:"key"` - TLSVerify bool `mapstructure:"tlsVerify" yaml:"tlsVerify"` - TLSConfig *tls.Config `mapstructure:"tlsConfig" yaml:"tlsConfig"` + Insecure bool `mapstructure:"insecure" yaml:"insecure"` + CACert serialize.PEMContent `mapstructure:"caCert" yaml:"caCert"` + Cert serialize.PEMContent `mapstructure:"cert" yaml:"cert"` + Key serialize.PEMContent `mapstructure:"key" yaml:"key"` + TLSVerify bool `mapstructure:"tlsVerify" yaml:"tlsVerify"` + TLSConfig *tls.Config `mapstructure:"tlsConfig" yaml:"tlsConfig"` } type StorageOption struct { @@ -562,58 +562,10 @@ type ReloadOption struct { Interval util.Duration `mapstructure:"interval" yaml:"interval"` } -// PEMContent supports load PEM format from file or just inline PEM format content -type PEMContent string - -func (p *PEMContent) UnmarshalJSON(b []byte) error { - var s string - err := json.Unmarshal(b, &s) - if err != nil { - return err - } - - return p.loadPEM(s) -} - -func (p *PEMContent) UnmarshalYAML(node *yaml.Node) error { - var s string - switch node.Kind { - case yaml.ScalarNode: - if err := node.Decode(&s); err != nil { - return err - } - default: - return errors.New("invalid pem content") - } - - return p.loadPEM(s) -} - -func (p *PEMContent) loadPEM(content string) error { - if content == "" { - *p = PEMContent("") - return nil - } - // inline PEM, just return - if strings.HasPrefix(strings.TrimSpace(content), "-----BEGIN ") { - val := strings.TrimSpace(content) - *p = PEMContent(val) - return nil - } - - file, err := os.ReadFile(content) - if err != nil { - return err - } - val := strings.TrimSpace(string(file)) - *p = PEMContent(val) - return nil -} - type tlsConfigFiles struct { - Cert PEMContent `yaml:"cert" json:"cert"` - Key PEMContent `yaml:"key" json:"key"` - CACert PEMContent `yaml:"caCert" json:"caCert"` + Cert serialize.PEMContent `yaml:"cert" json:"cert"` + Key serialize.PEMContent `yaml:"key" json:"key"` + CACert serialize.PEMContent `yaml:"caCert" json:"caCert"` } type TLSConfig struct { diff --git a/client/config/peerhost_test.go b/client/config/peerhost_test.go index b77ef5064..7c657e1b7 100644 --- a/client/config/peerhost_test.go +++ b/client/config/peerhost_test.go @@ -31,6 +31,7 @@ import ( "d7y.io/dragonfly/v2/cmd/dependency/base" "d7y.io/dragonfly/v2/manager/model" "d7y.io/dragonfly/v2/pkg/dfnet" + "d7y.io/dragonfly/v2/pkg/serialize" "d7y.io/dragonfly/v2/pkg/unit" ) @@ -225,9 +226,9 @@ func TestPeerHostOption_Load(t *testing.T) { _cert, _ := os.ReadFile("./testdata/certs/sca.crt") _key, _ := os.ReadFile("./testdata/certs/sca.key") - caCert := PEMContent(strings.TrimSpace(string(_caCert))) - cert := PEMContent(strings.TrimSpace(string(_cert))) - key := PEMContent(strings.TrimSpace(string(_key))) + caCert := serialize.PEMContent(strings.TrimSpace(string(_caCert))) + cert := serialize.PEMContent(strings.TrimSpace(string(_cert))) + key := serialize.PEMContent(strings.TrimSpace(string(_key))) peerHostOption := &DaemonOption{ Options: base.Options{ diff --git a/cmd/dependency/dependency.go b/cmd/dependency/dependency.go index 9488ee02c..a1538cc3e 100644 --- a/cmd/dependency/dependency.go +++ b/cmd/dependency/dependency.go @@ -50,6 +50,7 @@ import ( "d7y.io/dragonfly/v2/pkg/dfpath" "d7y.io/dragonfly/v2/pkg/net/fqdn" "d7y.io/dragonfly/v2/pkg/net/ip" + "d7y.io/dragonfly/v2/pkg/serialize" "d7y.io/dragonfly/v2/pkg/unit" "d7y.io/dragonfly/v2/version" ) @@ -238,7 +239,7 @@ func initDecoderConfig(dc *mapstructure.DecoderConfig) { reflect.TypeOf(util.Duration{}), reflect.TypeOf(&config.ProxyOption{}), reflect.TypeOf(config.TCPListenPortRange{}), - reflect.TypeOf(config.PEMContent("")), + reflect.TypeOf(serialize.PEMContent("")), reflect.TypeOf(config.URL{}), reflect.TypeOf(config.CertPool{}), reflect.TypeOf(config.Regexp{}): diff --git a/manager/config/config.go b/manager/config/config.go index 448f850d4..4ab2155ac 100644 --- a/manager/config/config.go +++ b/manager/config/config.go @@ -25,6 +25,7 @@ import ( "d7y.io/dragonfly/v2/cmd/dependency/base" "d7y.io/dragonfly/v2/pkg/objectstorage" + "d7y.io/dragonfly/v2/pkg/serialize" ) type Config struct { @@ -250,10 +251,10 @@ type SecurityConfig struct { Enable bool `yaml:"enable" mapstructure:"enable"` // CACert is file path PEM-encoded certificate - CACert string `mapstructure:"caCert" yaml:"caCert"` + CACert serialize.PEMContent `mapstructure:"caCert" yaml:"caCert"` // CAKey is file path of PEM-encoded private key. - CAKey string `mapstructure:"caKey" yaml:"caKey"` + CAKey serialize.PEMContent `mapstructure:"caKey" yaml:"caKey"` } // New config instance. diff --git a/manager/manager.go b/manager/manager.go index b9d1c3d9b..4c1663133 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -157,7 +157,7 @@ func New(cfg *config.Config, d dfpath.Dfpath) (*Server, error) { // Initialize global certificate. var options []rpcserver.Option if cfg.Security.Enable { - cert, err := tls.LoadX509KeyPair(cfg.Security.CACert, cfg.Security.CAKey) + cert, err := tls.X509KeyPair([]byte(cfg.Security.CACert), []byte(cfg.Security.CAKey)) if err != nil { return nil, err } diff --git a/pkg/serialize/pemcontent.go b/pkg/serialize/pemcontent.go new file mode 100644 index 000000000..6c90e15ef --- /dev/null +++ b/pkg/serialize/pemcontent.go @@ -0,0 +1,74 @@ +/* + * Copyright 2022 The Dragonfly Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package serialize + +import ( + "encoding/json" + "errors" + "os" + "strings" + + "gopkg.in/yaml.v3" +) + +// PEMContent supports load PEM format from file or just inline PEM format content +type PEMContent string + +func (p *PEMContent) UnmarshalJSON(b []byte) error { + var s string + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + + return p.loadPEM(s) +} + +func (p *PEMContent) UnmarshalYAML(node *yaml.Node) error { + var s string + switch node.Kind { + case yaml.ScalarNode: + if err := node.Decode(&s); err != nil { + return err + } + default: + return errors.New("invalid pem content") + } + + return p.loadPEM(s) +} + +func (p *PEMContent) loadPEM(content string) error { + if content == "" { + *p = PEMContent("") + return nil + } + // inline PEM, just return + if strings.HasPrefix(strings.TrimSpace(content), "-----BEGIN ") { + val := strings.TrimSpace(content) + *p = PEMContent(val) + return nil + } + + file, err := os.ReadFile(content) + if err != nil { + return err + } + val := strings.TrimSpace(string(file)) + *p = PEMContent(val) + return nil +}