Let's Encrypt support.

This commit is contained in:
Gustavo Niemeyer 2017-02-08 14:29:23 -02:00
parent 65998c5554
commit c70d35213a
2 changed files with 63 additions and 15 deletions

73
main.go
View File

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"crypto/tls"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@ -14,12 +15,26 @@ import (
"strings" "strings"
"text/template" "text/template"
"time" "time"
"golang.org/x/crypto/acme/autocert"
) )
var httpFlag = flag.String("http", ":8080", "Serve HTTP at given address") var (
var httpsFlag = flag.String("https", "", "Serve HTTPS at given address") httpFlag = flag.String("http", ":8080", "Serve HTTP at given address")
var certFlag = flag.String("cert", "", "Use the provided TLS certificate") httpsFlag = flag.String("https", "", "Serve HTTPS at given address")
var keyFlag = flag.String("key", "", "Use the provided TLS key") certFlag = flag.String("cert", "", "Use the provided TLS certificate")
keyFlag = flag.String("key", "", "Use the provided TLS key")
acmeFlag = flag.String("acme", "", "Auto-request TLS certs and store in given directory")
)
var httpServer = &http.Server{
ReadTimeout: 20 * time.Second,
WriteTimeout: 20 * time.Second,
}
var httpClient = &http.Client{
Timeout: 10 * time.Second,
}
func main() { func main() {
if err := run(); err != nil { if err := run(); err != nil {
@ -36,20 +51,56 @@ func run() error {
if *httpFlag == "" && *httpsFlag == "" { if *httpFlag == "" && *httpsFlag == "" {
return fmt.Errorf("must provide -http and/or -https") return fmt.Errorf("must provide -http and/or -https")
} }
if (*httpsFlag != "" || *certFlag != "" || *keyFlag != "") && (*httpsFlag == "" || *certFlag == "" || *keyFlag == "") { if *acmeFlag != "" && *httpsFlag == "" {
return fmt.Errorf("cannot use -acme without -https")
}
if *acmeFlag != "" && (*certFlag != "" || *keyFlag != "") {
return fmt.Errorf("cannot provide -acme with -key or -cert")
}
if *acmeFlag == "" && (*httpsFlag != "" || *certFlag != "" || *keyFlag != "") && (*httpsFlag == "" || *certFlag == "" || *keyFlag == "") {
return fmt.Errorf("-https -cert and -key must be used together") return fmt.Errorf("-https -cert and -key must be used together")
} }
ch := make(chan error, 2) ch := make(chan error, 2)
if *acmeFlag != "" {
// So a potential error is seen upfront.
if err := os.MkdirAll(*acmeFlag, 0700); err != nil {
return err
}
}
if *httpFlag != "" { if *httpFlag != "" {
server := *httpServer
server.Addr = *httpFlag
go func() { go func() {
ch <- http.ListenAndServe(*httpFlag, nil) ch <- server.ListenAndServe()
}() }()
} }
if *httpsFlag != "" { if *httpsFlag != "" {
server := *httpServer
server.Addr = *httpsFlag
if *acmeFlag != "" {
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache(*acmeFlag),
RenewBefore: 24 * 30 * time.Hour,
HostPolicy: autocert.HostWhitelist(
"localhost",
"gopkg.in",
"p1.gopkg.in",
"p2.gopkg.in",
"p3.gopkg.in",
"mup.labix.org",
),
Email: "gustavo@niemeyer.net",
}
server.TLSConfig = &tls.Config{
GetCertificate: m.GetCertificate,
}
}
go func() { go func() {
ch <- http.ListenAndServeTLS(*httpsFlag, *certFlag, *keyFlag, nil) ch <- server.ListenAndServeTLS(*certFlag, *keyFlag)
}() }()
} }
return <-ch return <-ch
@ -144,8 +195,8 @@ func (repo *Repo) GopkgVersionRoot(version Version) string {
} }
} }
var patternOld = regexp.MustCompile(`^/(?:([a-z0-9][-a-z0-9]+)/)?((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(-unstable)?)/([a-zA-Z][-a-zA-Z0-9]*)(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`) var patternOld = regexp.MustCompile(`^/(?:([a-z0-9][-a-z0-9]+)/)?((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(?:-unstable)?)/([a-zA-Z][-a-zA-Z0-9]*)(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)
var patternNew = regexp.MustCompile(`^/(?:([a-zA-Z0-9][-a-zA-Z0-9]+)/)?([a-zA-Z][-.a-zA-Z0-9]*)\.((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(-unstable)?)(?:\.git)?((?:/[a-zA-Z0-9][-.a-zA-Z0-9]*)*)$`) var patternNew = regexp.MustCompile(`^/(?:([a-zA-Z0-9][-a-zA-Z0-9]+)/)?([a-zA-Z][-.a-zA-Z0-9]*)\.((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(?:-unstable)?)(?:\.git)?((?:/[a-zA-Z0-9][-.a-zA-Z0-9]*)*)$`)
func handler(resp http.ResponseWriter, req *http.Request) { func handler(resp http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/health-check" { if req.URL.Path == "/health-check" {
@ -183,7 +234,7 @@ func handler(resp http.ResponseWriter, req *http.Request) {
repo := &Repo{ repo := &Repo{
User: m[1], User: m[1],
Name: m[2], Name: m[2],
SubPath: m[5], SubPath: m[4],
OldFormat: oldFormat, OldFormat: oldFormat,
FullVersion: InvalidVersion, FullVersion: InvalidVersion,
} }
@ -258,8 +309,6 @@ func sendNotFound(resp http.ResponseWriter, msg string, args ...interface{}) {
resp.Write([]byte(msg)) resp.Write([]byte(msg))
} }
var httpClient = &http.Client{Timeout: 10 * time.Second}
const refsSuffix = ".git/info/refs?service=git-upload-pack" const refsSuffix = ".git/info/refs?service=git-upload-pack"
var ErrNoRepo = errors.New("repository not found in GitHub") var ErrNoRepo = errors.New("repository not found in GitHub")

View File

@ -299,7 +299,6 @@ func renderPackagePage(resp http.ResponseWriter, req *http.Request, repo *Repo)
gotResp <- true gotResp <- true
}() }()
r := 0 r := 0
for r < wantResps { for r < wantResps {
select { select {