From 147a00e429ac62330b30995862849d2c2e90d28b Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Tue, 5 Dec 2017 20:56:57 -0500 Subject: [PATCH] Only serve over HTTPS, optionally auto-generating certificates Because MoneyGo requires sending passwords and session cookies, we should never serve over HTTP. While we're at it, make it more convenient for folks to test this out by adding a config option to auto-generate self-signed certificates. --- Gopkg.lock | 16 +++++++++++----- README.md | 16 +++++++++++----- example_config.ini | 21 ++++++++++++++++++--- internal/config/config.go | 14 ++++++++++++++ main.go | 19 +++++++++++++++++-- 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index a2e3b6f..e792b6d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -5,7 +5,7 @@ branch = "master" name = "github.com/aclindsa/gorp" packages = ["."] - revision = "d53dbb52439a458ae75f574d9420f66b6489441d" + revision = "4735379e1f46302b58b985d8172a53988aad93b4" [[projects]] name = "github.com/aclindsa/ofxgo" @@ -25,11 +25,17 @@ revision = "a0583e0143b1624142adab07e0e97fe106d99561" version = "v1.3" +[[projects]] + branch = "master" + name = "github.com/kabukky/httpscerts" + packages = ["."] + revision = "617593d7dcb39c9ed617bb62c5e2056244d02184" + [[projects]] branch = "master" name = "github.com/lib/pq" packages = [".","oid"] - revision = "8c6ee72f3e6bcb1542298dd5f76cb74af9742cec" + revision = "83612a56d3dd153a94a629cd64925371c9adad78" [[projects]] name = "github.com/mattn/go-sqlite3" @@ -47,13 +53,13 @@ branch = "master" name = "golang.org/x/net" packages = ["context"] - revision = "9dfe39835686865bff950a07b394c12a98ddc811" + revision = "a8b9294777976932365dabb6640cf1468d95c70f" [[projects]] branch = "master" name = "golang.org/x/text" packages = ["currency","internal","internal/format","internal/gen","internal/tag","language","unicode/cldr"] - revision = "88f656faf3f37f690df1a32515b479415e1a6769" + revision = "57961680700a5336d15015c8c50686ca5ba362a4" [[projects]] name = "gopkg.in/gcfg.v1" @@ -70,6 +76,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "de6a009267b8a81e29fc30f4bb7431c32ca42650d6cfd458324324f3f63abbff" + inputs-digest = "ad90bfdaa27132d84af5979b27d0960663bd13d57510566071056e1d4bb0d503" solver-name = "gps-cdcl" solver-version = 1 diff --git a/README.md b/README.md index f15e709..47bb548 100644 --- a/README.md +++ b/README.md @@ -63,15 +63,21 @@ cusip_list.csv file and re-run the `go generate ...` command. ## Running -Assuming you're in the same directory you ran the above installation commands -from, running MoneyGo is then as easy as: +MoneyGo requires HTTPS or FCGI (no HTTP). Before starting the server, you will +want to edit the example configuration file +(src/github.com/aclindsa/moneygo/example_config.ini) to point to your own SSL +certificate/key OR set 'generate-certs-if-absent = true' in the '[http]' section +of the config file. + +Then, assuming you're in the same directory you ran the above installation +commands from, running MoneyGo is as easy as: $ ./bin/moneygo -config src/github.com/aclindsa/moneygo/example_config.ini -You should then be able to explore MoneyGo by visiting http://localhost:8080 in +You should then be able to explore MoneyGo by visiting https://localhost:8443 in your browser. Editing the configuration file supplied will allow you to modify -several settings including the port used and whether to serve via FastCGI -instead of HTTP (the default). +several settings including the port used, SSL certificate locations, and whether +to serve via FastCGI instead of HTTPS (the default). ## Missing Features diff --git a/example_config.ini b/example_config.ini index 861fdea..1c6dddf 100644 --- a/example_config.ini +++ b/example_config.ini @@ -1,10 +1,10 @@ [moneygo] -# Whether to serve as FastCGI (default is false, for HTTP) +# Whether to serve as FastCGI (default is false, for HTTPS) fcgi = false -# Port to serve FCGI or HTTP on -port = 8080 +# Port on which to serve HTTPS or FCGI +port = 8443 # Base directory for serving files out of. This should point to the root of the # moneygo source directory @@ -25,3 +25,18 @@ db-type = sqlite3 # Postgres documentation: https://godoc.org/github.com/lib/pq # example DSN: "postgres://user:password@localhost/dbname" db-dsn = file:moneygo.sqlite?cache=shared&mode=rwc + + +[https] +# If 'fcgi = false', the following paths to a SSL certificate and the paired +# private key are used when serving HTTPS +cert-file = ./cert.pem +key-file = ./key.pem + +# Attempt to generate self-signed certificates if the certificate files +# specified above are missing or invalid. This should *never* be set to 'true' +# for any environment where security is important (including but not limited to +# production systems) +generate-certs-if-absent = false +# A CSV list of hostnames to generate the above certs for +generate-certs-hosts = localhost,127.0.0.1 diff --git a/internal/config/config.go b/internal/config/config.go index 5d71d7c..ecfb1cd 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -55,8 +55,16 @@ type MoneyGo struct { DSN string `gcfg:"db-dsn"` // 'Data Source Name' for database connection } +type Https struct { + CertFile string `gcfg:"cert-file"` + KeyFile string `gcfg:"key-file"` + GenerateCerts bool `gcfg:"generate-certs-if-absent"` // Generate certificates if missing + GenerateCertsHosts string `gcfg:"generate-certs-hosts"` // Hostnames to generate certificates for if missing and GenerateCerts==true +} + type Config struct { MoneyGo MoneyGo + Https Https } func ReadConfig(filename string) (*Config, error) { @@ -68,6 +76,12 @@ func ReadConfig(filename string) (*Config, error) { DBType: SQLite, DSN: "file:moneygo.sqlite?cache=shared&mode=rwc", }, + Https: Https{ + CertFile: "./cert.pem", + KeyFile: "./key.pem", + GenerateCerts: false, + GenerateCertsHosts: "localhost", + }, } err := gcfg.ReadFileInto(&cfg, filename) diff --git a/main.go b/main.go index 1a78a62..2baf7c0 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "github.com/aclindsa/moneygo/internal/config" "github.com/aclindsa/moneygo/internal/db" "github.com/aclindsa/moneygo/internal/handlers" + "github.com/kabukky/httpscerts" "log" "net" "net/http" @@ -89,10 +90,24 @@ func main() { log.Fatal(err) } - log.Printf("Serving on port %d out of directory: %s", cfg.MoneyGo.Port, cfg.MoneyGo.Basedir) if cfg.MoneyGo.Fcgi { + log.Printf("Serving via FCGI on port %d out of directory: %s", cfg.MoneyGo.Port, cfg.MoneyGo.Basedir) fcgi.Serve(listener, servemux) } else { - http.Serve(listener, servemux) + cert := cfg.Https.CertFile + key := cfg.Https.KeyFile + + if err := httpscerts.Check(cert, key); err != nil { + if !cfg.Https.GenerateCerts { + log.Fatalf("HTTPS certficates not found at '%s' and '%s'. If you would like for them to be auto-generated for you, specify 'generate-certs-if-absent = true' in your config file at '%s'", cert, key, configFile) + } + + err = httpscerts.Generate(cert, key, cfg.Https.GenerateCertsHosts) + if err != nil { + log.Fatalf("Error: Generating HTTPS cert/key at '%s' and '%s' failed: %s", cert, key, err) + } + } + log.Printf("Serving via HTTPS on port %d out of directory: %s", cfg.MoneyGo.Port, cfg.MoneyGo.Basedir) + http.ServeTLS(listener, servemux, cert, key) } }