TLS Support

main
Drew Bednar 2 months ago
parent 25f844d841
commit 687d2940c2

3
.gitignore vendored

@ -27,3 +27,6 @@ tmp/
*.db
*.db-shm
*.db-wal
# certs
*.pem

@ -10,7 +10,6 @@ PHONEY: serve
# SQLite Commands
sql-cli:
sqlite3 $(SQL_DATABASE) -cmd ".headers on" -cmd ".mode box" -cmd ".tables"
@ -29,4 +28,9 @@ check-system-deps:
@command -v air > /dev/null || (echo "Missing air command. go install github.com/air-verse/air@latest"; exit 1)
@command -v sqlite3 > /dev/null || (echo "Missing sqlite3 command. brew install sqlite"; exit 1)
@command -v migrate > /dev/null || (echo "Missing migrate command. go install -tags 'sqlite3' github.com/golang-migrate/migrate/v4/cmd/migrate@latest"; exit 1)
@echo "System dependencies fulfilled 👍"
@echo "System dependencies fulfilled 👍"
# Certs
local-certs:
cd ./tls && go run /usr/local/go/src/crypto/tls/generate_cert.go --rsa-bits=2048 --host=localhost

@ -246,4 +246,8 @@ It has:
- Expires/ Max-Age for roughly 3 days
- httpOnly: true
- Secure: true
- SameSite: None
- SameSite: None
## Local TLS Certs
https://github.com/FiloSottile/mkcert Can be used to create local certs with a trusted CA installed on the machine.

@ -1,6 +1,7 @@
package main
import (
"crypto/tls"
"flag"
"fmt"
"log/slog"
@ -11,7 +12,6 @@ import (
rdb "git.runcible.io/learning/ratchet/internal/database"
"git.runcible.io/learning/ratchet/internal/logging"
"git.runcible.io/learning/ratchet/internal/server"
"github.com/alexedwards/scs/sqlite3store"
"github.com/alexedwards/scs/v2"
_ "github.com/mattn/go-sqlite3"
// "git.runcible.io/learning/ratchet"
@ -30,6 +30,8 @@ func main() {
port := flag.String("port", "5001", "HTTP port")
logLevel := flag.String("logging", "INFO", "Logging Level. Valid values [INFO, DEBUG, WARN, ERROR].")
dbPath := flag.String("database", "./ratchet.db", "A path to a sqlite3 database")
certPath := flag.String("cert", "./tls/cert.pem", "A public cert in .pem format")
keyPath := flag.String("key", "./tls/key.pem", "A private key in .pem format")
// must call parse or all values will be the defaults
flag.Parse()
@ -54,19 +56,72 @@ func main() {
// SessionManager
sm := scs.New()
sm.Store = sqlite3store.New(db)
sm.Lifetime = 12 * time.Hour
// Propagate build information to root package to share globally
// ratchet.Version = strings.TrimPrefix(version, "")
// ratchet.Commit = commit
server := server.NewRatchetServer(logger, tc, db, sm)
app := server.NewRatchetApp(logger, tc, db, sm)
// these two elliptic curves have assembly implementations
tlsConfig := tls.Config{
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256},
// example of cipher suites usage. These are ignored if TLS 1.3 is used
// CipherSuites: []uint16{
// tls.TLS_AES_128_GCM_SHA256,
// tls.TLS_AES_256_GCM_SHA384,
// tls.TLS_CHACHA20_POLY1305_SHA256,
// tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
// tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
// tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
// },
// example of explicitly setting TLS versions supported.
// you do this for older browsers or for devices like micros that
// have hardware limitations.
// MinVersion: tls.VersionTLS10,
// MaxVersion: tls.VersionTLS12,
}
// START SERVING REQUESTS
slog.Debug("Herp dirp!")
slog.Info(fmt.Sprintf("Listening on http://%s:%s", *addr, *port))
//log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%s", *addr, *port), server))
// there is no log.Fatal equivalent. This is an approximation of the behavior
err = http.ListenAndServe(fmt.Sprintf("%s:%s", *addr, *port), server)
srv := &http.Server{
Addr: fmt.Sprintf("%s:%s", *addr, *port),
Handler: app,
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
TLSConfig: &tlsConfig,
// Server wide timeouts.
// IdleTimeout by default go uses keep-alives on accepted connetions.
// this lowers the default timeout. If you set read timeout but not idle
// then the idle becomes the readtimeout. Be careful.
IdleTimeout: time.Minute,
// If the request headers or body are still being read 5 seconds after the
// request is first accepted, then Go will close the underlying connection
// Care close. User won't recieve any http response
// See also http.Server also provides a ReadHeaderTimeout setting. Would allow
// per route timeouts.
ReadTimeout: 5 * time.Second,
// The WriteTimeout setting will close the underlying connection if our server
// attempts to write to the connection after a given period. When using TLS
// it's sensible to set WriteTimeout above ReadTimeout
// Its important to bear in mind that writes made by a handler are buffered and
// written to the connection as one when the handler returns. Therefore, the
// idea of WriteTimeout is generally not to prevent long-running handlers, but
// to prevent the data that the handler returns from taking too long to write.
WriteTimeout: 10 * time.Second,
// the maximum number of bytes the server will read when parsing request headers.
// default is one mb. Exceeding this returns a 431 Request Header Fields Too Large response
// btw go adds 4096 bytes to the number you provide.
MaxHeaderBytes: 524288, // 0.5 mb
}
slog.Info(fmt.Sprintf("Listening on https://%s", srv.Addr))
err = srv.ListenAndServeTLS(*certPath, *keyPath)
slog.Error(err.Error())
os.Exit(1)

@ -129,7 +129,7 @@ func handleSnippetView(logger *slog.Logger, tc *TemplateCache, sm *scs.SessionMa
// }
data := newTemplateData(r, sm)
data.Snippet = snippet
data.Flash = flash
// data.Flash = flash
renderTemplate(w, r, tc, http.StatusOK, "view.go.tmpl", data)
})
}

@ -10,7 +10,7 @@ import (
"github.com/go-playground/form/v4"
)
type RatchetServer struct {
type RatchetApp struct {
http.Handler
logger *slog.Logger
@ -22,8 +22,8 @@ type RatchetServer struct {
sessionManager *scs.SessionManager
}
func NewRatchetServer(logger *slog.Logger, tc *TemplateCache, db *sql.DB, sm *scs.SessionManager) *RatchetServer {
rs := new(RatchetServer)
func NewRatchetApp(logger *slog.Logger, tc *TemplateCache, db *sql.DB, sm *scs.SessionManager) *RatchetApp {
rs := new(RatchetApp)
rs.logger = logger
rs.snippetService = &model.SnippetService{DB: db}
rs.formDecoder = form.NewDecoder()

@ -133,7 +133,7 @@ func renderTemplate(w http.ResponseWriter, r *http.Request, tc *TemplateCache, s
serverError(w, r, err)
return
}
w.Header().Set("Content-Length", "this isn't an integer!")
w.WriteHeader(status)
buf.WriteTo(w)

Loading…
Cancel
Save