diff --git a/api.go b/api.go index 96e22bd5..d3bd5726 100644 --- a/api.go +++ b/api.go @@ -1,10 +1,12 @@ package headscale import ( + "bytes" "encoding/binary" "encoding/json" "errors" "fmt" + "html/template" "io" "net/http" "strings" @@ -38,6 +40,28 @@ func (h *Headscale) KeyHandler(ctx *gin.Context) { ) } +type registerWebAPITemplateConfig struct { + Key string +} + +var registerWebAPITemplate = template.Must( + template.New("registerweb").Parse(` + +

headscale

+

+ Run the command below in the headscale server to add this machine to your network: +

+ +

+ + headscale -n NAMESPACE nodes register --key {{.Key}} + +

+ + + `), +) + // RegisterWebAPI shows a simple message in the browser to point to the CLI // Listens in /register. func (h *Headscale) RegisterWebAPI(ctx *gin.Context) { @@ -48,24 +72,22 @@ func (h *Headscale) RegisterWebAPI(ctx *gin.Context) { return } - ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(` - - -

headscale

-

- Run the command below in the headscale server to add this machine to your network: -

+ var content bytes.Buffer + if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{ + Key: machineKeyStr, + }); err != nil { + log.Error(). + Str("func", "RegisterWebAPI"). + Err(err). + Msg("Could not render register web API template") + ctx.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render register web API template"), + ) + } -

- - headscale -n NAMESPACE nodes register --key %s - -

- - - - - `, machineKeyStr))) + ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes()) } // RegistrationHandler handles the actual registration process of a machine diff --git a/apple_mobileconfig.go b/apple_mobileconfig.go index 2e454df8..e5d9eede 100644 --- a/apple_mobileconfig.go +++ b/apple_mobileconfig.go @@ -2,8 +2,8 @@ package headscale import ( "bytes" + "html/template" "net/http" - "text/template" "github.com/gin-gonic/gin" "github.com/gofrs/uuid" diff --git a/oidc.go b/oidc.go index d481e028..120a4cff 100644 --- a/oidc.go +++ b/oidc.go @@ -1,11 +1,13 @@ package headscale import ( + "bytes" "context" "crypto/rand" "encoding/hex" "errors" "fmt" + "html/template" "net/http" "regexp" "strings" @@ -108,6 +110,22 @@ func (h *Headscale) RegisterOIDC(ctx *gin.Context) { ctx.Redirect(http.StatusFound, authURL) } +type oidcCallbackTemplateConfig struct { + User string + Verb string +} + +var oidcCallbackTemplate = template.Must( + template.New("oidccallback").Parse(` + +

headscale

+

+ {{.Verb}} as {{.User}}, you can now close this window. +

+ + `), +) + // OIDCCallback handles the callback from the OIDC endpoint // Retrieves the mkey from the state cache and adds the machine to the users email namespace // TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities @@ -239,17 +257,24 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { h.RefreshMachine(machine, requestedTime) - ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(` - - -

headscale

-

- Reuthenticated as %s, you can now close this window. -

- - + var content bytes.Buffer + if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ + User: claims.Email, + Verb: "Reauthenticated", + }); err != nil { + log.Error(). + Str("func", "OIDCCallback"). + Str("type", "reauthenticate"). + Err(err). + Msg("Could not render OIDC callback template") + ctx.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render OIDC callback template"), + ) + } -`, claims.Email))) + ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes()) return } @@ -314,17 +339,24 @@ func (h *Headscale) OIDCCallback(ctx *gin.Context) { h.db.Save(&machine) } - ctx.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(` - - -

headscale

-

- Authenticated as %s, you can now close this window. -

- - + var content bytes.Buffer + if err := oidcCallbackTemplate.Execute(&content, oidcCallbackTemplateConfig{ + User: claims.Email, + Verb: "Authenticated", + }); err != nil { + log.Error(). + Str("func", "OIDCCallback"). + Str("type", "authenticate"). + Err(err). + Msg("Could not render OIDC callback template") + ctx.Data( + http.StatusInternalServerError, + "text/html; charset=utf-8", + []byte("Could not render OIDC callback template"), + ) + } -`, claims.Email))) + ctx.Data(http.StatusOK, "text/html; charset=utf-8", content.Bytes()) return } diff --git a/swagger.go b/swagger.go index 9e62d393..bad348db 100644 --- a/swagger.go +++ b/swagger.go @@ -3,8 +3,8 @@ package headscale import ( "bytes" _ "embed" + "html/template" "net/http" - "text/template" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log"