Skip to content

Commit

Permalink
Changed all the html into go using go-elem
Browse files Browse the repository at this point in the history
    Created templates package in ./hscontrol/templates.
    Moved the registerWebAPITemplate into the templates package as a function to be called.

    Replaced the apple and windows html files with go-elem.
  • Loading branch information
amha-mersha committed Sep 30, 2024
1 parent 63035cd commit 1e8fc3e
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 293 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.23.0

require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/chasefleming/elem-go v0.29.0
github.com/coder/websocket v1.8.12
github.com/coreos/go-oidc/v3 v3.11.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chasefleming/elem-go v0.29.0 h1:WwrjQcVn6xldhexluvl2Z3sgKi9HTMuzWeEXO4PHsmg=
github.com/chasefleming/elem-go v0.29.0/go.mod h1:hz73qILBIKnTgOujnSMtEj20/epI+f6vg71RUilJAA4=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
Expand Down
93 changes: 37 additions & 56 deletions hscontrol/handlers.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package hscontrol

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"html/template"
"net/http"
"strconv"
"time"

"github.com/chasefleming/elem-go"
"github.com/chasefleming/elem-go/attrs"
"github.com/chasefleming/elem-go/styles"
"github.com/gorilla/mux"
"github.com/juanfont/headscale/hscontrol/templates"
"github.com/rs/zerolog/log"
"tailscale.com/tailcfg"
"tailscale.com/types/key"
Expand Down Expand Up @@ -134,38 +136,37 @@ func (h *Headscale) HealthHandler(
respond(nil)
}

type registerWebAPITemplateConfig struct {
Key string
var codeStyleRegisterWebAPI = styles.Props{
styles.Display: "block",
styles.Padding: "20px",
styles.Border: "1px solid #bbb",
styles.BackgroundColor: "#eee",
}

var registerWebAPITemplate = template.Must(
template.New("registerweb").Parse(`
<html>
<head>
<title>Registration - Headscale</title>
<meta name=viewport content="width=device-width, initial-scale=1">
<style>
body {
font-family: sans;
}
code {
display: block;
padding: 20px;
border: 1px solid #bbb;
background-color: #eee;
}
</style>
</head>
<body>
<h1>headscale</h1>
<h2>Machine registration</h2>
<p>
Run the command below in the headscale server to add this machine to your network:
</p>
<code>headscale nodes register --user USERNAME --key {{.Key}}</code>
</body>
</html>
`))
func registerWebHTML(key string) *elem.Element {
return elem.Html(nil,
elem.Head(
nil,
elem.Title(nil, elem.Text("Registration - Headscale")),
elem.Meta(attrs.Props{
attrs.Name: "viewport",
attrs.Content: "width=device-width, initial-scale=1",
}),
),
elem.Body(attrs.Props{
attrs.Style: styles.Props{
styles.FontFamily: "sans",
}.ToInline(),
},
elem.H1(nil, elem.Text("headscale")),
elem.H2(nil, elem.Text("Machine registration")),
elem.P(nil, elem.Text("Run the command below in the headscale server to add this machine to your network:")),
elem.Code(attrs.Props{attrs.Style: codeStyleRegisterWebAPI.ToInline()},
elem.Text(fmt.Sprintf("headscale nodes register --user USERNAME --key %s", key)),
),
),
)
}

// RegisterWebAPI shows a simple message in the browser to point to the CLI
// Listens in /register/:nkey.
Expand Down Expand Up @@ -202,34 +203,14 @@ func (h *Headscale) RegisterWebAPI(
return
}

var content bytes.Buffer
if err := registerWebAPITemplate.Execute(&content, registerWebAPITemplateConfig{
Key: machineKey.String(),
}); err != nil {
log.Error().
Str("func", "RegisterWebAPI").
Err(err).
Msg("Could not render register web API template")
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError)
_, err = writer.Write([]byte("Could not render register web API template"))
if err != nil {
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
writer.WriteHeader(http.StatusOK)
if _, err := writer.Write([]byte(registerWebHTML(machineKey.String()).Render())); err != nil {
if _, err := writer.Write([]byte(templates.RegisterWeb(machineKey.String()).Render())); err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
}

return
}

writer.Header().Set("Content-Type", "text/html; charset=utf-8")
writer.WriteHeader(http.StatusOK)
_, err = writer.Write(content.Bytes())
if err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
}
}
66 changes: 5 additions & 61 deletions hscontrol/platform_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,19 @@ import (

"github.com/gofrs/uuid/v5"
"github.com/gorilla/mux"
"github.com/juanfont/headscale/hscontrol/templates"
"github.com/rs/zerolog/log"
)

//go:embed templates/apple.html
var appleTemplate string

//go:embed templates/windows.html
var windowsTemplate string

// WindowsConfigMessage shows a simple message in the browser for how to configure the Windows Tailscale client.
func (h *Headscale) WindowsConfigMessage(
writer http.ResponseWriter,
req *http.Request,
) {
winTemplate := template.Must(template.New("windows").Parse(windowsTemplate))
config := map[string]interface{}{
"URL": h.cfg.ServerURL,
}

var payload bytes.Buffer
if err := winTemplate.Execute(&payload, config); err != nil {
log.Error().
Str("handler", "WindowsRegConfig").
Err(err).
Msg("Could not render Windows index template")

writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError)
_, err := writer.Write([]byte("Could not render Windows index template"))
if err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
}

return
}

writer.Header().Set("Content-Type", "text/html; charset=utf-8")
writer.WriteHeader(http.StatusOK)
_, err := writer.Write(payload.Bytes())
if err != nil {

if _, err := writer.Write([]byte(templates.Windows(h.cfg.ServerURL).Render())); err != nil {
log.Error().
Caller().
Err(err).
Expand All @@ -64,36 +34,10 @@ func (h *Headscale) AppleConfigMessage(
writer http.ResponseWriter,
req *http.Request,
) {
appleTemplate := template.Must(template.New("apple").Parse(appleTemplate))

config := map[string]interface{}{
"URL": h.cfg.ServerURL,
}

var payload bytes.Buffer
if err := appleTemplate.Execute(&payload, config); err != nil {
log.Error().
Str("handler", "AppleMobileConfig").
Err(err).
Msg("Could not render Apple index template")

writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError)
_, err := writer.Write([]byte("Could not render Apple index template"))
if err != nil {
log.Error().
Caller().
Err(err).
Msg("Failed to write response")
}

return
}

writer.Header().Set("Content-Type", "text/html; charset=utf-8")
writer.WriteHeader(http.StatusOK)
_, err := writer.Write(payload.Bytes())
if err != nil {

if _, err := writer.Write([]byte(templates.Apple(h.cfg.ServerURL).Render())); err != nil {
log.Error().
Caller().
Err(err).
Expand Down
149 changes: 149 additions & 0 deletions hscontrol/templates/apple.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package templates

import (
"fmt"

"github.com/chasefleming/elem-go"
"github.com/chasefleming/elem-go/attrs"
)

func Apple(url string) *elem.Element {
return HtmlStructure(
elem.Title(nil,
elem.Text("headscale - Apple")),
elem.Body(attrs.Props{
attrs.Style: bodyStyle.ToInline(),
},
headerOne("headscale: iOS configuration"),
headerTwo("GUI"),
elem.Ol(nil,
elem.Li(nil,
elem.Text("Install the official Tailscale iOS client from the"),
elem.A(attrs.Props{attrs.Href: "https://apps.apple.com/app/tailscale/id1470499037"},
elem.Text("App store"),
),
),
elem.Li(nil,
elem.Text("Open Tailscale and make sure you are"),
elem.I(nil, elem.Text("not")),
elem.Text("logged in to any account"),
),
elem.Li(nil,
elem.Text("Open Settings on the iOS device"),
),
elem.Li(nil,
elem.Text(`Scroll down to the "third party apps" section, under "Game Center" or "TV Provider"`),
),
elem.Li(nil,
elem.Text("Find Tailscale and select it"),
elem.Ul(nil,
elem.Li(nil,
elem.Text(`If the iOS device was previously logged into Tailscale, switch the "Reset Keychain" toggle to "on"`),
),
),
),
elem.Li(nil,
elem.Text(fmt.Sprintf(`Enter "%s" under "Alternate Coordination Server URL`,url)),
),
elem.Li(nil,
elem.Text("Restart the app by closing it from the iOS app switcher, open the app and select the regular sign in option"),
elem.I(nil, elem.Text("(non-SSO)")),
elem.Text(". It should open up to the headscale authentication page."),
),
elem.Li(nil,
elem.Text("Enter your credentials and log in. Headscale should now be working on your iOS device"),
),
),
headerOne("headscale: macOS configuration"),
headerTwo("Command line"),
elem.P(nil,
elem.Text("Use Tailscale's login command to add your profile:"),
),
elem.Pre(nil,
elem.Code(nil,
elem.Text(fmt.Sprintf("tailscale login --login-server %s",url)),
),
),
headerTwo("GUI"),
elem.Ol(nil,
elem.Li(nil,
elem.Text("ALT + Click the Tailscale icon in the menu and hover over the Debug menu"),
),
elem.Li(nil,
elem.Text(`Under "Custom Login Server", select "Add Account..."`),
),
elem.Li(nil,
elem.Text(fmt.Sprintf(`Enter "%s" of the headscale instance and press "Add Account"`,url)),
),
elem.Li(nil,
elem.Text(`Follow the login procedure in the browser`),
),
),
headerTwo("Profiles"),
elem.P(nil,
elem.Text("Headscale can be set to the default server by installing a Headscale configuration profile:"),
),
elem.P(nil,
elem.A(attrs.Props{attrs.Href: "/apple/macos-app-store", attrs.Download: "headscale_macos.mobileconfig"},
elem.Text("macOS AppStore profile"),
),
elem.A(attrs.Props{attrs.Href: "/apple/macos-standalone", attrs.Download: "headscale_macos.mobileconfig"},
elem.Text("macOS Standalone profile"),
),
),
elem.Ol(nil,
elem.Li(nil,
elem.Text("Download the profile, then open it. When it has been opened, there should be a notification that a profile can be installed"),
),
elem.Li(nil,
elem.Text(`Open System Preferences and go to "Profiles"`),
),
elem.Li(nil,
elem.Text(`Find and install the Headscale profile`),
),
elem.Li(nil,
elem.Text(`Restart Tailscale.app and log in`),
),
),
elem.P(nil, elem.Text("Or")),
elem.P(nil,
elem.Text("Use your terminal to configure the default setting for Tailscale by issuing:"),
),
elem.Ul(nil,
elem.Li(nil,
elem.Text(`for app store client:`),
elem.Code(nil,
elem.Text(fmt.Sprintf(`defaults write io.tailscale.ipn.macos ControlURL %s`,url)),
),
),
elem.Li(nil,
elem.Text(`for standalone client:`),
elem.Code(nil,
elem.Text(fmt.Sprintf(`defaults write io.tailscale.ipn.macsys ControlURL %s`,url)),
),
),
),
elem.P(nil,
elem.Text("Restart Tailscale.app and log in."),
),
headerThree("Caution"),
elem.P(nil,
elem.Text("You should always download and inspect the profile before installing it:"),
),
elem.Ul(nil,
elem.Li(nil,
elem.Text(`for app store client: `),
elem.Code(nil,
elem.Text(fmt.Sprintf(`curl %s/apple/macos-app-store`,url)),
),
),
elem.Li(nil,
elem.Text(`for standalone client: `),
elem.Code(nil,
elem.Text(fmt.Sprintf(`curl %s/apple/macos-standalone`,url)),
),
),
),
),
)
}
Loading

0 comments on commit 1e8fc3e

Please sign in to comment.