Skip to content

Commit

Permalink
golink: listen on HTTPS and redirect HTTP traffic
Browse files Browse the repository at this point in the history
Updates #9

On tailnets with TLS enabled serve HTTP traffic with a separate
redirectHandler which sends requests to our HTTPS listener destination.

Add `-L` to documented examples of using `curl` to follow these
redirects if present.

Signed-off-by: Patrick O'Doherty <[email protected]>
  • Loading branch information
patrickod committed Dec 8, 2023
1 parent c9212a4 commit 2fc65c3
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 8 deletions.
83 changes: 77 additions & 6 deletions golink.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"bytes"
"context"
"crypto/rand"
"crypto/tls"
"embed"
"encoding/base64"
"encoding/json"
Expand Down Expand Up @@ -169,18 +170,78 @@ func Run() error {
if err := srv.Start(); err != nil {
return err
}
localClient, _ = srv.LocalClient()

l80, err := srv.Listen("tcp", ":80")
// create tsNet server and wait for it to be ready & connected.
localClient, _ = srv.LocalClient()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_, err = srv.Up(ctx)
if err != nil {
return err
}

log.Printf("Serving http://%s/ ...", *hostname)
if err := http.Serve(l80, serveHandler()); err != nil {
return err
enableTLS := len(srv.CertDomains()) > 0
if enableTLS {
// warm the certificate cache for all cert domains to prevent users waiting
// on ACME challenges in-line on their first request.
for _, d := range srv.CertDomains() {
log.Printf("Provisioning TLS certificate for %s ...", d)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

_, _, err := localClient.CertPair(ctx, d)
if err != nil {
return err
}
}

redirectFqdn := srv.CertDomains()[0]
// HTTP listener that redirects to our HTTPS listener.
log.Println("Listening on :80")
httpListener, err := srv.Listen("tcp", ":80")
if err != nil {
return err
}
go func() error {
log.Printf("Serving http://%s/ ...", *hostname)
if err := http.Serve(httpListener, redirectHandler(redirectFqdn)); err != nil {
return err
}
return nil
}()

log.Println("Listening on :443")
httpsListener, err := srv.Listen("tcp", ":443")
if err != nil {
return err
}
s := http.Server{
Addr: ":443",
Handler: serveHandler(),
TLSConfig: &tls.Config{
GetCertificate: localClient.GetCertificate,
},
}

log.Printf("Serving https://%s/\n", redirectFqdn)
if err := s.ServeTLS(httpsListener, "", ""); err != nil {
return err
}
return nil
} else {
// no TLS, just serve on :80
log.Println("Listening on :80")
httpListener, err := srv.Listen("tcp", ":80")
if err != nil {
return err
}
log.Printf("Serving http://%s/ ...", *hostname)
if err := http.Serve(httpListener, serveHandler()); err != nil {
return err
}
return nil
}
return nil

}

var (
Expand Down Expand Up @@ -286,6 +347,16 @@ func deleteLinkStats(link *Link) {
db.DeleteStats(link.Short)
}

// redirectHandler returns the http.Handler for serving all plaintext HTTP
// requests. It redirects all requests to the HTTPs version of the same URL.
func redirectHandler(hostname string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
newUrl := fmt.Sprintf("https://%s%s", hostname, path)
http.Redirect(w, r, newUrl, http.StatusMovedPermanently)
})
}

// serverHandler returns the main http.Handler for serving all requests.
func serveHandler() http.Handler {
mux := http.NewServeMux()
Expand Down
4 changes: 2 additions & 2 deletions tmpl/help.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,15 @@ <h2 id="api">Application Programming Interface (API)</h2>
Visit <a href="/.export">go/.export</a> to export all saved links and their metadata in <a href="https://jsonlines.org/">JSON Lines format</a>.
This is useful to create data snapshots that can be restored later.

<pre>{{`$ curl go/.export
<pre>{{`$ curl -L go/.export
{"Short":"go","Long":"http://go","Created":"2022-05-31T13:04:44.741457796-07:00","LastEdit":"2022-05-31T13:04:44.741457796-07:00","Owner":"[email protected]","Clicks":1}
{"Short":"slack","Long":"https://company.slack.com/{{if .Path}}channels/{{PathEscape .Path}}{{end}}","Created":"2022-06-17T18:05:43.562948451Z","LastEdit":"2022-06-17T18:06:35.811398Z","Owner":"[email protected]","Clicks":4}`}}
</pre>

<p>
Create a new link by sending a POST request with a <code>short</code> and <code>long</code> value:

<pre>{{`$ curl -d short=cs -d long=https://cs.github.com/ go
<pre>{{`$ curl -L -d short=cs -d long=https://cs.github.com/ go
{"Short":"cs","Long":"https://cs.github.com/","Created":"2022-06-03T22:15:29.993978392Z","LastEdit":"2022-06-03T22:15:29.993978392Z","Owner":"[email protected]"}`}}
</pre>

Expand Down

0 comments on commit 2fc65c3

Please sign in to comment.