diff --git a/app.go b/app.go index ba2fce74..800b0a43 100644 --- a/app.go +++ b/app.go @@ -178,9 +178,9 @@ func run(args options) { } address := net.JoinHostPort(config.BindHost, strconv.Itoa(config.TLS.PortHTTPS)) // validate current TLS config and update warnings (it could have been loaded from file) - data, err := validateCertificates(config.TLS) - if err != nil { - log.Fatal(err) + data := validateCertificates(config.TLS) + if data.WarningValidation != "" { + log.Fatal(data.WarningValidation) os.Exit(1) } config.TLS = data // update warnings diff --git a/control.go b/control.go index c507def2..af1a6d4c 100644 --- a/control.go +++ b/control.go @@ -78,9 +78,7 @@ func writeAllConfigsAndReloadDNS() error { func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { err := writeAllConfigsAndReloadDNS() if err != nil { - errorText := fmt.Sprintf("Couldn't write config file: %s", err) - log.Println(errorText) - http.Error(w, errorText, http.StatusInternalServerError) + httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } returnOK(w) @@ -1039,20 +1037,7 @@ func handleInstallConfigure(w http.ResponseWriter, r *http.Request) { // TLS // --- func handleTLSStatus(w http.ResponseWriter, r *http.Request) { - data := config.TLS - if data.CertificateChain != "" { - encoded := base64.StdEncoding.EncodeToString([]byte(data.CertificateChain)) - data.CertificateChain = string(encoded) - } - if data.PrivateKey != "" { - encoded := base64.StdEncoding.EncodeToString([]byte(data.PrivateKey)) - data.PrivateKey = string(encoded) - } - err := json.NewEncoder(w).Encode(&data) - if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) - return - } + marshalTLS(w, config.TLS) } func handleTLSValidate(w http.ResponseWriter, r *http.Request) { @@ -1062,11 +1047,8 @@ func handleTLSValidate(w http.ResponseWriter, r *http.Request) { return } - data, err = validateCertificates(data) - if err != nil { - httpError(w, http.StatusBadRequest, "New TLS configuration does not validate: %s", err) - return - } + data = validateCertificates(data) + marshalTLS(w, data) } func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { @@ -1076,18 +1058,21 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { return } - data, err = validateCertificates(data) + restartHTTPS := false + data = validateCertificates(data) + if data.WarningValidation == "" { + if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { + log.Printf("tls config settings have changed, will restart HTTPS server") + restartHTTPS = true + } + config.TLS = data + } + err = writeAllConfigsAndReloadDNS() if err != nil { - httpError(w, http.StatusBadRequest, "New TLS configuration does not validate: %s", err) + httpError(w, http.StatusInternalServerError, "Couldn't write config file: %s", err) return } - restartHTTPS := false - if !reflect.DeepEqual(config.TLS.tlsConfigSettings, data.tlsConfigSettings) { - log.Printf("tls config settings have changed, will restart HTTPS server") - restartHTTPS = true - } - config.TLS = data - httpUpdateConfigReloadDNSReturnOK(w, r) + marshalTLS(w, data) // this needs to be done in a goroutine because Shutdown() is a blocking call, and it will block // until all requests are finished, and _we_ are inside a request right now, so it will block indefinitely if restartHTTPS && httpsServer.server != nil { @@ -1098,7 +1083,7 @@ func handleTLSConfigure(w http.ResponseWriter, r *http.Request) { } } -func validateCertificates(data tlsConfig) (tlsConfig, error) { +func validateCertificates(data tlsConfig) tlsConfig { var err error // clear out status for certificates @@ -1131,13 +1116,15 @@ func validateCertificates(data tlsConfig) (tlsConfig, error) { for _, cert := range certs { parsed, err := x509.ParseCertificate(cert.Bytes) if err != nil { - return data, errorx.Decorate(err, "Failed to parse certificate") + data.WarningValidation = fmt.Sprintf("Failed to parse certificate: %s", err) + return data } parsedCerts = append(parsedCerts, parsed) } if len(parsedCerts) == 0 { - return data, fmt.Errorf("You have specified an empty certificate") + data.WarningValidation = fmt.Sprintf("You have specified an empty certificate") + return data } // spew.Dump(parsedCerts) @@ -1223,13 +1210,15 @@ func validateCertificates(data tlsConfig) (tlsConfig, error) { } if key == nil { - return data, fmt.Errorf("No valid keys were found") + data.WarningValidation = "No valid keys were found" + return data } // parse the decoded key _, keytype, err := parsePrivateKey(key.Bytes) if err != nil { - return data, errorx.Decorate(err, "Failed to parse private key") + data.WarningValidation = fmt.Sprintf("Failed to parse private key: %s", err) + return data } data.ValidKey = true @@ -1240,11 +1229,12 @@ func validateCertificates(data tlsConfig) (tlsConfig, error) { if data.PrivateKey != "" && data.CertificateChain != "" { _, err = tls.X509KeyPair([]byte(data.CertificateChain), []byte(data.PrivateKey)) if err != nil { - return data, errorx.Decorate(err, "Invalid certificate or key") + data.WarningValidation = fmt.Sprintf("Invalid certificate or key: %s", err) + return data } } - return data, nil + return data } // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates @@ -1299,6 +1289,23 @@ func unmarshalTLS(r *http.Request) (tlsConfig, error) { return data, nil } +func marshalTLS(w http.ResponseWriter, data tlsConfig) { + w.Header().Set("Content-Type", "application/json") + if data.CertificateChain != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(data.CertificateChain)) + data.CertificateChain = string(encoded) + } + if data.PrivateKey != "" { + encoded := base64.StdEncoding.EncodeToString([]byte(data.PrivateKey)) + data.PrivateKey = string(encoded) + } + err := json.NewEncoder(w).Encode(data) + if err != nil { + httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) + return + } +} + // ------------------------ // registration of handlers // ------------------------