diff options
Diffstat (limited to 'system')
-rw-r--r-- | system/api/handlers.go | 14 | ||||
-rw-r--r-- | system/db/config.go | 5 | ||||
-rw-r--r-- | system/tls/devcerts.go | 148 | ||||
-rw-r--r-- | system/tls/enable.go | 6 | ||||
-rw-r--r-- | system/tls/enabledev.go | 29 |
5 files changed, 188 insertions, 14 deletions
diff --git a/system/api/handlers.go b/system/api/handlers.go index 788b2a0..7b59dbd 100644 --- a/system/api/handlers.go +++ b/system/api/handlers.go @@ -180,15 +180,6 @@ func toJSON(data []string) ([]byte, error) { return buf.Bytes(), nil } -func wrapJSON(json []byte) []byte { - var buf = &bytes.Buffer{} - buf.Write([]byte(`{"data":`)) - buf.Write(json) - buf.Write([]byte(`}`)) - - return buf.Bytes() -} - // sendData() should be used any time you want to communicate // data back to a foreign client func sendData(res http.ResponseWriter, data []byte, code int) { @@ -196,7 +187,10 @@ func sendData(res http.ResponseWriter, data []byte, code int) { res.Header().Set("Access-Control-Allow-Origin", "*") res.Header().Set("Content-Type", "application/json") res.WriteHeader(code) - res.Write(data) + _, err := res.Write(data) + if err != nil { + log.Println("Error writing to response in sendData") + } } // SendPreflight is used to respond to a cross-origin "OPTIONS" request diff --git a/system/db/config.go b/system/db/config.go index ce76021..45b3952 100644 --- a/system/db/config.go +++ b/system/db/config.go @@ -108,7 +108,10 @@ func ConfigAll() ([]byte, error) { val := &bytes.Buffer{} err := store.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("__config")) - val.Write(b.Get([]byte("settings"))) + _, err := val.Write(b.Get([]byte("settings"))) + if err != nil { + return err + } return nil }) diff --git a/system/tls/devcerts.go b/system/tls/devcerts.go new file mode 100644 index 0000000..b41f099 --- /dev/null +++ b/system/tls/devcerts.go @@ -0,0 +1,148 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Modified 2016 by Steve Manuel, Boss Sauce Creative, LLC +// All modifications are relicensed under the same BSD license +// found in the LICENSE file. + +// Generate a self-signed X.509 certificate for a TLS server. Outputs to +// 'devcerts/cert.pem' and 'devcerts/key.pem' and will overwrite existing files. + +package tls + +import ( + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "log" + "math/big" + "net" + "os" + "path/filepath" + "time" + + "github.com/ponzu-cms/ponzu/system/db" +) + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) + os.Exit(2) + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} + +func setupDev() { + var priv interface{} + var err error + + priv, err = rsa.GenerateKey(rand.Reader, 2048) + + if err != nil { + log.Fatalf("failed to generate private key: %s", err) + } + + notBefore := time.Now() + notAfter := notBefore.Add(time.Hour * 24 * 30) // valid for 30 days + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + log.Fatalf("failed to generate serial number: %s", err) + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Ponzu Dev Server"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + hosts := []string{"localhost", "0.0.0.0"} + domain := db.ConfigCache("domain") + if domain != "" { + hosts = append(hosts, domain) + } + + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + // make all certs CA + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) + if err != nil { + log.Fatalln("Failed to create certificate:", err) + } + + // overwrite/create directory for devcerts + pwd, err := os.Getwd() + if err != nil { + log.Fatalln("Couldn't find working directory to locate or save dev certificates:", err) + } + + vendorTLSPath := filepath.Join(pwd, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "system", "tls") + devcertsPath := filepath.Join(vendorTLSPath, "devcerts") + + // clear all old certs if found + err = os.RemoveAll(devcertsPath) + if err != nil { + log.Fatalln("Failed to remove old files from dev certificate directory:", err) + } + + err = os.Mkdir(devcertsPath, os.ModePerm|os.ModePerm) + if err != nil { + log.Fatalln("Failed to create directory to locate or save dev certificates:", err) + } + + certOut, err := os.Create(filepath.Join(devcertsPath, "cert.pem")) + if err != nil { + log.Fatalln("Failed to open devcerts/cert.pem for writing:", err) + } + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certOut.Close() + + keyOut, err := os.OpenFile(filepath.Join(devcertsPath, "key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + log.Fatalln("Failed to open devcerts/key.pem for writing:", err) + return + } + pem.Encode(keyOut, pemBlockForKey(priv)) + keyOut.Close() +} diff --git a/system/tls/enable.go b/system/tls/enable.go index 04f032a..c6f65b3 100644 --- a/system/tls/enable.go +++ b/system/tls/enable.go @@ -65,7 +65,8 @@ func setup() { } -// Enable runs the setup for creating or locating certificates and starts the TLS server +// Enable runs the setup for creating or locating production certificates and +// starts the TLS server func Enable() { setup() @@ -74,6 +75,5 @@ func Enable() { TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, } - go log.Fatalln(server.ListenAndServeTLS("", "")) - fmt.Println("Server listening for HTTPS requests...") + log.Fatalln(server.ListenAndServeTLS("", "")) } diff --git a/system/tls/enabledev.go b/system/tls/enabledev.go new file mode 100644 index 0000000..3550fc0 --- /dev/null +++ b/system/tls/enabledev.go @@ -0,0 +1,29 @@ +package tls + +import ( + "log" + "net/http" + "os" + "path/filepath" +) + +// EnableDev generates self-signed SSL certificates to use HTTPS & HTTP/2 while +// working in a development environment. The certs are saved in a different +// directory than the production certs (from Let's Encrypt), so that the +// acme/autocert package doesn't mistake them for it's own. +// Additionally, a TLS server is started using the default http mux. +func EnableDev() { + setupDev() + + pwd, err := os.Getwd() + if err != nil { + log.Fatalln("Couldn't find working directory to activate dev certificates:", err) + } + + vendorPath := filepath.Join(pwd, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "system", "tls") + + cert := filepath.Join(vendorPath, "devcerts", "cert.pem") + key := filepath.Join(vendorPath, "devcerts", "key.pem") + + log.Fatalln(http.ListenAndServeTLS(":10443", cert, key, nil)) +} |