- Uses certificate and key files provided by admin in config - Let's Encrypt integration planned, but not even close to working - Initial HTTP3 Support added
This commit is contained in:
parent
68d7a5e8c3
commit
9151bfb3be
6 changed files with 250 additions and 42 deletions
117
auth-new/tls.go
117
auth-new/tls.go
|
@ -5,8 +5,10 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -40,62 +42,99 @@ func (l *leUser) GetPrivateKey() crypto.PrivateKey {
|
|||
return l.Key
|
||||
}
|
||||
|
||||
func TlsFromConfig() (*tls.Config, error) {
|
||||
// Return the path to the certificate file (.crt), the key file (.key) and any errors
|
||||
func TlsFromConfig() (string, string, error) {
|
||||
if config.GlobalConfig.SSL.UseLetsEncrypt != nil && *config.GlobalConfig.SSL.UseLetsEncrypt {
|
||||
return tlsFromLetsEncrypt()
|
||||
} else {
|
||||
return tlsFromFile()
|
||||
}
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
||||
func tlsFromLetsEncrypt() (*tls.Config, error) {
|
||||
// Verifies that the relevant config entries are set and are paths to readable files
|
||||
func tlsFromFile() (string, string, error) {
|
||||
sslConf := config.GlobalConfig.SSL
|
||||
if sslConf.CertificateFile == nil {
|
||||
return "", "", errors.New("need a path to a certificate file to use for tls")
|
||||
}
|
||||
if sslConf.CertKeyFile == nil {
|
||||
return "", "", errors.New("need a path to a certificate key file to use for tls")
|
||||
}
|
||||
certInfo, err := os.Stat(*sslConf.CertificateFile)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if certInfo.IsDir() {
|
||||
return "", "", errors.New("certificate file is a directory, needs to be a file")
|
||||
}
|
||||
keyInfo, err := os.Stat(*sslConf.CertKeyFile)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if keyInfo.IsDir() {
|
||||
return "", "", errors.New("key file is a directory, needs to be a file")
|
||||
}
|
||||
return *sslConf.CertificateFile, *sslConf.CertKeyFile, nil
|
||||
}
|
||||
|
||||
// Get the LetsEncrypt generated certifiates and store them in temporary files for the server to use
|
||||
// If the certificate is too old, requests a new one.
|
||||
func tlsFromLetsEncrypt() (string, string, error) {
|
||||
metadata, err := dbgen.ServerMetadata.First()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", "", err
|
||||
}
|
||||
if !metadata.LELastUpdate.Valid {
|
||||
return generateLetsEncryptCert(metadata)
|
||||
if err = generateLetsEncryptCert(metadata); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
} else if metadata.LELastUpdate.Time.Add(time.Hour * 24 * 60).Before(time.Now()) {
|
||||
// Let's Encrypt certificates last for 90 days. It is recommended to renew every 60 days
|
||||
// See https://letsencrypt.org/docs/faq/#what-is-the-lifetime-for-let-s-encrypt-certificates-for-how-long-are-they-valid
|
||||
return generateLetsEncryptCert(metadata)
|
||||
if err = generateLetsEncryptCert(metadata); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
||||
// (Re-)Generate a Lets Encrypt certificate using the provided details in the config
|
||||
// Automatically stores the newly generated certificate in the db, encrypting beforehand
|
||||
func generateLetsEncryptCert(metadata *models.ServerMetadata) (*tls.Config, error) {
|
||||
// (Re-)Generate a Lets Encrypt certificate using the provided details in the config.
|
||||
// Automatically stores the newly generated certificate in the db, encrypting beforehand.
|
||||
// Also updates the metadata with the new data.
|
||||
// Does not write the cert to a temporary file.
|
||||
func generateLetsEncryptCert(metadata *models.ServerMetadata) error {
|
||||
encKey := []byte(config.GlobalConfig.Storage.EncryptionKey)
|
||||
// Follow https://go-acme.github.io/lego/usage/library/index.html
|
||||
var userPrivateKey *ecdsa.PrivateKey
|
||||
var err error
|
||||
if len(metadata.LEUserPrivKey) == 0 {
|
||||
userPrivateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
marshalled, err := x509.MarshalECPrivateKey(userPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
encryptedKey, err := Encrypt(
|
||||
[]byte(config.GlobalConfig.Storage.EncryptionKey),
|
||||
encKey,
|
||||
marshalled,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
metadata.LEUserPrivKey = encryptedKey
|
||||
} else {
|
||||
decryptedKey, err := Decrypt([]byte(config.GlobalConfig.Storage.EncryptionKey), metadata.LEUserPrivKey)
|
||||
decryptedKey, err := Decrypt(encKey, metadata.LEUserPrivKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
userPrivateKey, err = x509.ParseECPrivateKey(decryptedKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
user := leUser{Email: *config.GlobalConfig.SSL.AdminMail}
|
||||
user := leUser{Email: *config.GlobalConfig.SSL.AdminMail, Key: userPrivateKey}
|
||||
leConfig := lego.NewConfig(&user)
|
||||
leConfig.CADirURL = strings.Replace(
|
||||
config.GlobalConfig.General.GetFullPublicUrl(),
|
||||
|
@ -107,22 +146,22 @@ func generateLetsEncryptCert(metadata *models.ServerMetadata) (*tls.Config, erro
|
|||
|
||||
leClient, err := lego.NewClient(leConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// TODO: Figure out these servers
|
||||
err = leClient.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "5002"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
err = leClient.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", "5001"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
reg, err := leClient.Registration.Register(
|
||||
registration.RegisterOptions{TermsOfServiceAgreed: true},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
user.Registration = reg
|
||||
req := certificate.ObtainRequest{
|
||||
|
@ -131,9 +170,35 @@ func generateLetsEncryptCert(metadata *models.ServerMetadata) (*tls.Config, erro
|
|||
}
|
||||
certificates, err := leClient.Certificate.Obtain(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
_ = certificates
|
||||
// TODO: Do something with certificates here
|
||||
panic("Not implemented")
|
||||
metadata.LELastUpdate = sql.NullTime{Valid: true, Time: time.Now()}
|
||||
metadata.LEDomain = certificates.Domain
|
||||
metadata.LECertStableUrl = certificates.CertStableURL
|
||||
metadata.LECertUrl = certificates.CertURL
|
||||
metadata.LECSR, err = Encrypt(encKey, certificates.CSR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metadata.LECertificate, err = Encrypt(encKey, certificates.Certificate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metadata.LECertificate, err = Encrypt(encKey, certificates.Certificate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metadata.LEPrivateKey, err = Encrypt(encKey, certificates.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
metadata.LEIssuerCertificate, err = Encrypt(encKey, certificates.IssuerCertificate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbgen.ServerMetadata.Save(metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -14,8 +14,10 @@ type ConfigSSL struct {
|
|||
HandleSSL bool `toml:"handle_ssl"` // Whether Linstrom should handle SSL encryption itself in case of http1/2
|
||||
// If Linstrom is to handle SSL, whether it should use LetsEncrypt for certificates
|
||||
UseLetsEncrypt *bool `toml:"use_lets_encrypt"`
|
||||
// Path to the certificate if Linstrom is to handle SSL while not using LetsEncrypt
|
||||
// Path to the certificate file (.crt) if Linstrom is to handle SSL while not using LetsEncrypt
|
||||
CertificateFile *string `toml:"certificate_file"`
|
||||
// Path to the certificate key file (.key) to handle SSL while not using LetsEncrypt
|
||||
CertKeyFile *string `toml:"cert_key_file"`
|
||||
// Mail adress to use in case of using LetsEncrypt
|
||||
AdminMail *string `toml:"admin_mail"`
|
||||
}
|
||||
|
@ -251,6 +253,14 @@ func (gc *ConfigGeneral) GetFullPublicUrl() string {
|
|||
return str
|
||||
}
|
||||
|
||||
func (gc *ConfigGeneral) GetFinalPublicPort() int {
|
||||
if gc.PublicPort != nil {
|
||||
return *gc.PublicPort
|
||||
} else {
|
||||
return gc.PrivatePort
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *ConfigStorage) BuildPostgresDSN() string {
|
||||
dsn := fmt.Sprintf(
|
||||
"host=%s user=%s password=%s dbname=%s port=%d",
|
||||
|
|
6
go.mod
6
go.mod
|
@ -33,11 +33,13 @@ require (
|
|||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-webauthn/x v0.1.20 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-tpm v0.9.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
|
@ -52,8 +54,12 @@ require (
|
|||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.64 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.52.0 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
|
|
18
go.sum
18
go.sum
|
@ -10,8 +10,12 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
|
|||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||
|
@ -27,6 +31,8 @@ github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JS
|
|||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-webauthn/webauthn v0.12.3 h1:hHQl1xkUuabUU9uS+ISNCMLs9z50p9mDUZI/FmkayNE=
|
||||
github.com/go-webauthn/webauthn v0.12.3/go.mod h1:4JRe8Z3W7HIw8NGEWn2fnUwecoDzkkeach/NnvhkqGY=
|
||||
github.com/go-webauthn/x v0.1.20 h1:brEBDqfiPtNNCdS/peu8gARtq8fIPsHz0VzpPjGvgiw=
|
||||
|
@ -44,8 +50,11 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc=
|
||||
github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
|
@ -88,12 +97,18 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
|||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/nrednav/cuid2 v1.0.1 h1:aYLDCmGxEij7xCdiV6GVSPSlqFOS6sqHKKvBeKjddVY=
|
||||
github.com/nrednav/cuid2 v1.0.1/go.mod h1:nH9lUYqbtoVsnpy20etw5q1guTjE99Xy4EpmnK5nKm0=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
|
@ -114,6 +129,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY
|
|||
github.com/yaronf/httpsign v0.3.2 h1:rBYYx9eHm60noI4oC24JAD2tJuM8AUDh9ErJO/FfzBs=
|
||||
github.com/yaronf/httpsign v0.3.2/go.mod h1:cYB/6toJrJnf4JTLVoo6IHzFH9/Zu1dcKmah4xfX2WA=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
|
@ -134,6 +151,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
40
web/public/middleware/httpUpgrade.go
Normal file
40
web/public/middleware/httpUpgrade.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package webmiddleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/config"
|
||||
)
|
||||
|
||||
func AddUpgradeHeader(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.ProtoMajor {
|
||||
case 1:
|
||||
// Always offer upgrade to http2
|
||||
headerText := fmt.Sprintf(
|
||||
"h2=\":%d\"; ma=3600",
|
||||
config.GlobalConfig.General.GetFinalPublicPort(),
|
||||
)
|
||||
// Offer upgrade to http3 if enabled
|
||||
if config.GlobalConfig.Experimental.Http3Support && config.GlobalConfig.SSL.HandleSSL {
|
||||
headerText = fmt.Sprintf(
|
||||
"h3=\":%d\"; ma=3600, %s",
|
||||
config.GlobalConfig.General.GetFinalPublicPort(),
|
||||
headerText,
|
||||
)
|
||||
}
|
||||
w.Header().Add("Alt-Svc", headerText)
|
||||
case 2:
|
||||
// Offer upgrade to http3 if enabled
|
||||
if config.GlobalConfig.Experimental.Http3Support && config.GlobalConfig.SSL.HandleSSL {
|
||||
headerText := fmt.Sprintf(
|
||||
"h3=\":%d\"; ma=3600",
|
||||
config.GlobalConfig.General.GetFinalPublicPort(),
|
||||
)
|
||||
w.Header().Add("Alt-Svc", headerText)
|
||||
}
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
|
@ -32,13 +32,18 @@ import (
|
|||
"net/http"
|
||||
|
||||
webutils "git.mstar.dev/mstar/goutils/http"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/auth-new"
|
||||
"git.mstar.dev/mstar/linstrom/config"
|
||||
"git.mstar.dev/mstar/linstrom/web/public/api"
|
||||
webmiddleware "git.mstar.dev/mstar/linstrom/web/public/middleware"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
server *http.Server
|
||||
server *http.Server
|
||||
quicServer *http3.Server
|
||||
}
|
||||
|
||||
func New(addr string, duckImg *string, duckFs fs.FS) *Server {
|
||||
|
@ -51,28 +56,92 @@ func New(addr string, duckImg *string, duckFs fs.FS) *Server {
|
|||
handler.HandleFunc("GET /errors/{name}", errorTypeHandler)
|
||||
handler.HandleFunc("GET /default-image", buildServeDefaultImage(duckImg, duckFs))
|
||||
handler.HandleFunc("GET /default-image.webp", buildServeDefaultImage(duckImg, duckFs))
|
||||
server := http.Server{
|
||||
Handler: webutils.ChainMiddlewares(
|
||||
handler,
|
||||
webutils.BuildLoggingMiddleware(
|
||||
true,
|
||||
[]string{"/assets"},
|
||||
map[string]string{"server": "public"},
|
||||
),
|
||||
webmiddleware.AppendFullPathMiddleware,
|
||||
webmiddleware.TraceRequestInfoMiddleware,
|
||||
rootHandler := webutils.ChainMiddlewares(
|
||||
handler,
|
||||
webutils.BuildLoggingMiddleware(
|
||||
true,
|
||||
[]string{"/assets"},
|
||||
map[string]string{"server": "public"},
|
||||
),
|
||||
Addr: addr,
|
||||
webmiddleware.AppendFullPathMiddleware,
|
||||
webmiddleware.TraceRequestInfoMiddleware,
|
||||
webmiddleware.AddUpgradeHeader,
|
||||
)
|
||||
server := http.Server{
|
||||
Handler: rootHandler,
|
||||
Addr: addr,
|
||||
}
|
||||
return &Server{&server}
|
||||
quicServer := http3.Server{
|
||||
Handler: rootHandler,
|
||||
Addr: addr,
|
||||
}
|
||||
if config.GlobalConfig.General.PublicPort != nil {
|
||||
quicServer.Port = *config.GlobalConfig.General.PublicPort
|
||||
}
|
||||
return &Server{server: &server, quicServer: &quicServer}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
return s.server.ListenAndServe()
|
||||
if config.GlobalConfig.SSL.HandleSSL {
|
||||
certFile, keyFile, err := auth.TlsFromConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if config.GlobalConfig.Experimental.Http3Support {
|
||||
errChan := make(chan error, 2)
|
||||
go func() {
|
||||
errChan <- s.server.ListenAndServeTLS(certFile, keyFile)
|
||||
}()
|
||||
go func() {
|
||||
errChan <- s.quicServer.ListenAndServeTLS(certFile, keyFile)
|
||||
}()
|
||||
|
||||
err := <-errChan
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
// Always gets two values back on the channel since both servers are running
|
||||
err = <-errChan
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return s.server.ListenAndServeTLS(certFile, keyFile)
|
||||
}
|
||||
} else {
|
||||
// But refuse http3 support here, since it doesn't work without tls
|
||||
return s.server.ListenAndServe()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
return s.server.Shutdown(context.Background())
|
||||
if config.GlobalConfig.SSL.HandleSSL && config.GlobalConfig.Experimental.Http3Support {
|
||||
errChan := make(chan error, 2)
|
||||
go func() {
|
||||
log.Debug().Msg("Stopping tcp server")
|
||||
errChan <- s.server.Shutdown(context.Background())
|
||||
log.Debug().Msg("Tcp server stopped")
|
||||
}()
|
||||
go func() {
|
||||
log.Debug().Msg("Stopping udp server")
|
||||
errChan <- s.quicServer.Shutdown(context.Background())
|
||||
log.Debug().Msg("Udp server stopped")
|
||||
}()
|
||||
|
||||
err := <-errChan
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
// Always gets two values back on the channel since both servers are running
|
||||
err = <-errChan
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return s.server.Shutdown(context.Background())
|
||||
}
|
||||
}
|
||||
|
||||
func buildServeDefaultImage(
|
||||
|
|
Loading…
Reference in a new issue