diff --git a/go.mod b/go.mod index dbac9a1..697cfb5 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,6 @@ go 1.15 require ( github.com/GeertJohan/go.rice v1.0.0 github.com/caddyserver/certmagic v0.12.0 + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de ) diff --git a/go.sum b/go.sum index 6d712d0..6368258 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= diff --git a/ui_handler.go b/ui_handler.go index 4f2fa2e..2dcf42c 100644 --- a/ui_handler.go +++ b/ui_handler.go @@ -1,8 +1,10 @@ package main import ( + "encoding/base64" "fmt" "github.com/GeertJohan/go.rice" + qrcode "github.com/skip2/go-qrcode" "html/template" "io" "log" @@ -30,6 +32,7 @@ type IndexData struct { Tokens map[string]TokenData Users map[string]User IsAdmin bool + QrCodes map[string]template.URL } type TunnelsData struct { @@ -205,6 +208,7 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request var tokens map[string]TokenData var users map[string]User + qrCodes := make(map[string]template.URL) if user.IsAdmin { tokens = h.db.GetTokens() @@ -216,6 +220,19 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request if tokenData.Owner == td.Owner { tokens[token] = td } + + loginUrl := fmt.Sprintf("https://%s/login?access_token=%s", h.config.WebUiDomain, token) + + var png []byte + png, err := qrcode.Encode(loginUrl, qrcode.Medium, 256) + if err != nil { + w.WriteHeader(500) + h.alertDialog(w, r, err.Error(), "/#/tokens") + return + } + + data := base64.StdEncoding.EncodeToString(png) + qrCodes[token] = template.URL("data:image/png;base64," + data) } users = make(map[string]User) @@ -228,9 +245,15 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request Tokens: tokens, Users: users, IsAdmin: user.IsAdmin, + QrCodes: qrCodes, } - tmpl.Execute(w, indexData) + err = tmpl.Execute(w, indexData) + if err != nil { + w.WriteHeader(500) + h.alertDialog(w, r, err.Error(), "/#/tokens") + return + } case "/tunnels": h.handleTunnels(w, r, tokenData) @@ -298,7 +321,12 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request tmpl.Execute(w, data) case "/logout": - cookie := &http.Cookie{Name: "access_token", Value: "", Secure: true, HttpOnly: true} + cookie := &http.Cookie{ + Name: "access_token", + Value: "", + Secure: true, + HttpOnly: true, + } http.SetCookie(w, cookie) http.Redirect(w, r, "/#/tunnels", 303) case "/loading": @@ -366,7 +394,13 @@ func (h *WebUiHandler) handleLogin(w http.ResponseWriter, r *http.Request) { token := tokenList[0] if h.auth.Authorized(token) { - cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true} + cookie := &http.Cookie{ + Name: "access_token", + Value: token, + Secure: true, + HttpOnly: true, + MaxAge: 86400 * 365, + } http.SetCookie(w, cookie) http.Redirect(w, r, "/#/tunnels", 303) } else { diff --git a/webui/index.tmpl b/webui/index.tmpl index ac6fe68..ce48c52 100644 --- a/webui/index.tmpl +++ b/webui/index.tmpl @@ -79,8 +79,11 @@