package config import ( "crypto/tls" "crypto/x509" "encoding/pem" "errors" "fmt" "os" "github.com/youmark/pkcs8" ) type tlsConfig struct { CAPath string `json:"capath" yaml:"capath"` KeyPath string `json:"keypath" yaml:"keypath"` CertPath string `json:"certpath" yaml:"certpath"` Password string `json:"password" yaml:"password"` SkipVerify bool `json:"skipverify" yaml:"skipverify"` ServerName string `json:"servername" yaml:"servername"` } type rabbitConfig struct { Broker string `json:"broker" yaml:"broker"` Username string `json:"username" yaml:"username"` Password string `json:"password" yaml:"password"` TLS *tlsConfig `json:"tls" yaml:"tls"` } func NewRabbitConfig() *rabbitConfig { return new(rabbitConfig) } func (conf *rabbitConfig) GenAddress(tls bool) string { if conf == nil { panic("rabbit config is nil") } address := "amqp://" if tls { address = "amqps://" } if conf.GetUsername() != "" && conf.GetPassword() != "" { address += conf.GetUsername() + ":" + conf.GetPassword() + "@" } address += conf.GetBroker() + "/" return address } func (conf *rabbitConfig) GetBroker() string { if conf == nil { panic("rabbit config is nil") } return conf.Broker } func (conf *rabbitConfig) SetBroker(broker string) *rabbitConfig { if conf == nil { panic("rabbit config is nil") } conf.Broker = broker return conf } func (conf *rabbitConfig) GetUsername() string { if conf == nil { panic("rabbit config is nil") } return conf.Username } func (conf *rabbitConfig) SetUsername(username string) *rabbitConfig { if conf == nil { panic("rabbit config is nil") } conf.Username = username return conf } func (conf *rabbitConfig) GetPassword() string { if conf == nil { panic("rabbit config is nil") } return conf.Password } func (conf *rabbitConfig) SetPassword(password string) *rabbitConfig { if conf == nil { panic("rabbit config is nil") } conf.Password = password return conf } func (conf *rabbitConfig) InitTLS() *rabbitConfig { if conf == nil { panic("rabbit config is nil") } conf.TLS = new(tlsConfig) return conf } func (conf *rabbitConfig) GetTLS() *tlsConfig { if conf == nil { panic("rabbit config is nil") } return conf.TLS } func (conf *tlsConfig) GetCAPath() string { if conf == nil { panic("rabbit tls is nil") } return conf.CAPath } func (conf *tlsConfig) SetCAPath(caPath string) *tlsConfig { if conf == nil { panic("rabbit tls is nil") } conf.CAPath = caPath return conf } func (conf *tlsConfig) GetKeyPath() string { if conf == nil { panic("rabbit tls is nil") } return conf.KeyPath } func (conf *tlsConfig) SetKeyPath(keyPath string) *tlsConfig { if conf == nil { panic("rabbit tls is nil") } conf.KeyPath = keyPath return conf } func (conf *tlsConfig) GetCertPath() string { if conf == nil { panic("rabbit tls is nil") } return conf.CertPath } func (conf *tlsConfig) SetCertPath(certPath string) *tlsConfig { if conf == nil { panic("rabbit tls is nil") } conf.CertPath = certPath return conf } func (conf *tlsConfig) GetPassword() string { if conf == nil { panic("rabbit tls is nil") } return conf.Password } func (conf *tlsConfig) SetPassword(password string) *tlsConfig { if conf == nil { panic("rabbit tls is nil") } conf.Password = password return conf } func (conf *tlsConfig) GetSkipVerify() bool { if conf == nil { panic("rabbit tls is nil") } return conf.SkipVerify } func (conf *tlsConfig) SetSkipVerify(skipVerify bool) *tlsConfig { if conf == nil { panic("rabbit tls is nil") } conf.SkipVerify = skipVerify return conf } func (conf *tlsConfig) GetServerName() string { if conf == nil { panic("rabbit tls is nil") } return conf.ServerName } func (conf *tlsConfig) SetServerName(serverName string) *tlsConfig { if conf == nil { panic("rabbit tls is nil") } conf.ServerName = serverName return conf } func (conf *tlsConfig) GenTLSConfig(tag string) (*tls.Config, error) { if conf == nil { return nil, nil } if conf.GetCAPath() == "" || conf.GetCertPath() == "" || conf.GetKeyPath() == "" { return nil, errors.New("rabbit tls not valid") } caPem, err := os.ReadFile(conf.GetCAPath()) if err != nil { return nil, err } certPool := x509.NewCertPool() certPool.AppendCertsFromPEM(caPem) keyPem, err := os.ReadFile(conf.GetKeyPath()) if err != nil { return nil, err } certPem, err := os.ReadFile(conf.GetCertPath()) if err != nil { return nil, err } pemBlock, err := parsePrivateKey(keyPem, []byte(conf.GetPassword())) if err != nil { return nil, err } cliCert, err := tls.X509KeyPair(certPem, pem.EncodeToMemory(pemBlock)) if err != nil { return nil, err } return &tls.Config{ Certificates: []tls.Certificate{cliCert}, RootCAs: certPool, ServerName: conf.GetServerName(), InsecureSkipVerify: conf.GetSkipVerify(), }, nil } func parsePrivateKey(key, password []byte) (*pem.Block, error) { block, _ := pem.Decode(key) if block == nil { return nil, errors.New("no valid pem") } var privateKey any var err error switch block.Type { case "RSA PRIVATE KEY": privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) case "PRIVATE KEY": privateKey, err = x509.ParsePKCS8PrivateKey(block.Bytes) case "ENCRYPTED PRIVATE KEY": privateKey, err = pkcs8.ParsePKCS8PrivateKey(block.Bytes, password) default: return nil, fmt.Errorf("unsupported key type: %s", block.Type) } if err != nil { return nil, err } pemBytes, err := x509.MarshalPKCS8PrivateKey(privateKey) if err != nil { return nil, err } return &pem.Block{ Type: "PRIVATE KEY", Bytes: pemBytes, }, nil } func rabbitConfigName() string { return "rabbit.json" }