mirror of
https://codeberg.org/Codeberg/pages-server.git
synced 2024-11-18 10:29:43 +00:00
Add HSTS & cipher suites, handle fallback cert errors & change default port to 443
This commit is contained in:
parent
0602811709
commit
7c70be21d7
3 changed files with 86 additions and 29 deletions
102
certificates.go
102
certificates.go
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
@ -12,38 +13,85 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fallbackCertKey, _ = rsa.GenerateKey(rand.Reader, 1024)
|
|
||||||
var fallbackCertSpecification = &x509.Certificate{
|
|
||||||
Subject: pkix.Name{
|
|
||||||
CommonName: strings.TrimPrefix(string(MainDomainSuffix), "."),
|
|
||||||
},
|
|
||||||
SerialNumber: big.NewInt(0),
|
|
||||||
NotBefore: time.Now(),
|
|
||||||
NotAfter: time.Now().AddDate(100, 0, 0),
|
|
||||||
}
|
|
||||||
var fallbackCertBytes, _ = x509.CreateCertificate(
|
|
||||||
rand.Reader,
|
|
||||||
fallbackCertSpecification,
|
|
||||||
fallbackCertSpecification,
|
|
||||||
fallbackCertKey.Public(),
|
|
||||||
fallbackCertKey,
|
|
||||||
)
|
|
||||||
var fallbackCert, _ = tls.X509KeyPair(pem.EncodeToMemory(&pem.Block{
|
|
||||||
Bytes: fallbackCertBytes,
|
|
||||||
Type: "CERTIFICATE",
|
|
||||||
}), pem.EncodeToMemory(&pem.Block{
|
|
||||||
Bytes: x509.MarshalPKCS1PrivateKey(fallbackCertKey),
|
|
||||||
Type: "RSA PRIVATE KEY",
|
|
||||||
}))
|
|
||||||
|
|
||||||
// tlsConfig contains the configuration for generating, serving and cleaning up Let's Encrypt certificates.
|
// tlsConfig contains the configuration for generating, serving and cleaning up Let's Encrypt certificates.
|
||||||
var tlsConfig = &tls.Config{
|
var tlsConfig = &tls.Config{
|
||||||
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
// TODO: check DNS name & get certificate from Let's Encrypt
|
// TODO: check DNS name & get certificate from Let's Encrypt
|
||||||
return &fallbackCert, nil
|
return FallbackCertificate(), nil
|
||||||
},
|
},
|
||||||
PreferServerCipherSuites: true,
|
PreferServerCipherSuites: true,
|
||||||
// TODO: optimize cipher suites, minimum TLS version, etc.
|
|
||||||
|
// generated 2021-07-13, Mozilla Guideline v5.6, Go 1.14.4, intermediate configuration
|
||||||
|
// https://ssl-config.mozilla.org/#server=go&version=1.14.4&config=intermediate&guideline=5.6
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
CipherSuites: []uint16{
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: HSTS header with includeSubdomains & preload for MainDomainSuffix and RawDomain
|
// GetHSTSHeader returns a HSTS header with includeSubdomains & preload for MainDomainSuffix and RawDomain, or an empty
|
||||||
|
// string for custom domains.
|
||||||
|
func GetHSTSHeader(host []byte) string {
|
||||||
|
if bytes.HasSuffix(host, MainDomainSuffix) || bytes.Equal(host, RawDomain) {
|
||||||
|
return "max-age=63072000; includeSubdomains; preload"
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fallbackCertificate *tls.Certificate
|
||||||
|
// FallbackCertificate generates a new self-signed TLS certificate on demand.
|
||||||
|
func FallbackCertificate() *tls.Certificate {
|
||||||
|
if fallbackCertificate != nil {
|
||||||
|
return fallbackCertificate
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackSerial, err := rand.Int(rand.Reader, (&big.Int{}).Lsh(big.NewInt(1), 159))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackCertKey, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackCertSpecification := &x509.Certificate{
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: strings.TrimPrefix(string(MainDomainSuffix), "."),
|
||||||
|
},
|
||||||
|
SerialNumber: fallbackSerial,
|
||||||
|
NotBefore: time.Now(),
|
||||||
|
NotAfter: time.Now().AddDate(100, 0, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackCertBytes, err := x509.CreateCertificate(
|
||||||
|
rand.Reader,
|
||||||
|
fallbackCertSpecification,
|
||||||
|
fallbackCertSpecification,
|
||||||
|
fallbackCertKey.Public(),
|
||||||
|
fallbackCertKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackCert, err := tls.X509KeyPair(pem.EncodeToMemory(&pem.Block{
|
||||||
|
Bytes: fallbackCertBytes,
|
||||||
|
Type: "CERTIFICATE",
|
||||||
|
}), pem.EncodeToMemory(&pem.Block{
|
||||||
|
Bytes: x509.MarshalPKCS1PrivateKey(fallbackCertKey),
|
||||||
|
Type: "RSA PRIVATE KEY",
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackCertificate = &fallbackCert
|
||||||
|
return fallbackCertificate
|
||||||
|
}
|
||||||
|
|
11
handler.go
11
handler.go
|
@ -28,6 +28,11 @@ func handler(ctx *fasthttp.RequestCtx) {
|
||||||
// Enable caching, but require revalidation to reduce confusion
|
// Enable caching, but require revalidation to reduce confusion
|
||||||
ctx.Response.Header.Set("Cache-Control", "must-revalidate")
|
ctx.Response.Header.Set("Cache-Control", "must-revalidate")
|
||||||
|
|
||||||
|
// Add HSTS for RawDomain and MainDomainSuffix
|
||||||
|
if hsts := GetHSTSHeader(ctx.Host()); hsts != "" {
|
||||||
|
ctx.Response.Header.Set("Strict-Transport-Security", hsts)
|
||||||
|
}
|
||||||
|
|
||||||
// Block all methods not required for static pages
|
// Block all methods not required for static pages
|
||||||
if !ctx.IsGet() && !ctx.IsHead() && !ctx.IsOptions() {
|
if !ctx.IsGet() && !ctx.IsHead() && !ctx.IsOptions() {
|
||||||
ctx.Response.Header.Set("Allow", "GET, HEAD, OPTIONS")
|
ctx.Response.Header.Set("Allow", "GET, HEAD, OPTIONS")
|
||||||
|
@ -275,7 +280,11 @@ func handler(ctx *fasthttp.RequestCtx) {
|
||||||
func returnErrorPage(ctx *fasthttp.RequestCtx, code int) {
|
func returnErrorPage(ctx *fasthttp.RequestCtx, code int) {
|
||||||
ctx.Response.SetStatusCode(code)
|
ctx.Response.SetStatusCode(code)
|
||||||
ctx.Response.Header.SetContentType("text/html; charset=utf-8")
|
ctx.Response.Header.SetContentType("text/html; charset=utf-8")
|
||||||
ctx.Response.SetBody(bytes.ReplaceAll(NotFoundPage, []byte("%status"), []byte(strconv.Itoa(code)+" "+fasthttp.StatusMessage(code))))
|
message := fasthttp.StatusMessage(code)
|
||||||
|
if code == fasthttp.StatusFailedDependency {
|
||||||
|
message += " - owner, repo or branch doesn't exist"
|
||||||
|
}
|
||||||
|
ctx.Response.SetBody(bytes.ReplaceAll(NotFoundPage, []byte("%status"), []byte(strconv.Itoa(code)+" "+message)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BranchExistanceCacheTimeout specifies the timeout for the default branch cache. It can be quite long.
|
// BranchExistanceCacheTimeout specifies the timeout for the default branch cache. It can be quite long.
|
||||||
|
|
2
main.go
2
main.go
|
@ -79,7 +79,7 @@ func main() {
|
||||||
GiteaRoot = bytes.TrimSuffix(GiteaRoot, []byte{'/'})
|
GiteaRoot = bytes.TrimSuffix(GiteaRoot, []byte{'/'})
|
||||||
|
|
||||||
// Use HOST and PORT environment variables to determine listening address
|
// Use HOST and PORT environment variables to determine listening address
|
||||||
address := fmt.Sprintf("%s:%s", envOr("HOST", "[::]"), envOr("PORT", "80"))
|
address := fmt.Sprintf("%s:%s", envOr("HOST", "[::]"), envOr("PORT", "443"))
|
||||||
fmt.Printf("Listening on https://%s\n", address)
|
fmt.Printf("Listening on https://%s\n", address)
|
||||||
|
|
||||||
// Enable compression by wrapping the handler() method with the compression function provided by FastHTTP
|
// Enable compression by wrapping the handler() method with the compression function provided by FastHTTP
|
||||||
|
|
Loading…
Reference in a new issue