package headscale import ( "bytes" "net/http" "text/template" "github.com/rs/zerolog/log" "github.com/gin-gonic/gin" "github.com/gofrs/uuid" ) // AppleMobileConfig shows a simple message in the browser to point to the CLI // Listens in /register func (h *Headscale) AppleMobileConfig(c *gin.Context) { t := template.Must(template.New("apple").Parse(`

Apple configuration profiles

This page provides configuration profiles for the official Tailscale clients for iOS and macOS.

The profiles will configure Tailscale.app to use {{.Url}} as its control server.

Caution

You should always inspect the profile before installing it:

curl {{.Url}}/apple/ios

curl {{.Url}}/apple/macos

Profiles

iOS

macOS

`)) config := map[string]interface{}{ "Url": h.cfg.ServerURL, } var payload bytes.Buffer if err := t.Execute(&payload, config); err != nil { log.Error(). Str("handler", "AppleMobileConfig"). Err(err). Msg("Could not render Apple index template") c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple index template")) return } c.Data(http.StatusOK, "text/html; charset=utf-8", payload.Bytes()) } func (h *Headscale) ApplePlatformConfig(c *gin.Context) { platform := c.Param("platform") id, err := uuid.NewV4() if err != nil { log.Error(). Str("handler", "ApplePlatformConfig"). Err(err). Msg("Failed not create UUID") c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Failed to create UUID")) return } contentId, err := uuid.NewV4() if err != nil { log.Error(). Str("handler", "ApplePlatformConfig"). Err(err). Msg("Failed not create UUID") c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Failed to create UUID")) return } platformConfig := AppleMobilePlatformConfig{ UUID: contentId, Url: h.cfg.ServerURL, } var payload bytes.Buffer switch platform { case "macos": if err := macosTemplate.Execute(&payload, platformConfig); err != nil { log.Error(). Str("handler", "ApplePlatformConfig"). Err(err). Msg("Could not render Apple macOS template") c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple macOS template")) return } case "ios": if err := iosTemplate.Execute(&payload, platformConfig); err != nil { log.Error(). Str("handler", "ApplePlatformConfig"). Err(err). Msg("Could not render Apple iOS template") c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple iOS template")) return } default: c.Data(http.StatusOK, "text/html; charset=utf-8", []byte("Invalid platform, only ios and macos is supported")) return } config := AppleMobileConfig{ UUID: id, Url: h.cfg.ServerURL, Payload: payload.String(), } var content bytes.Buffer if err := commonTemplate.Execute(&content, config); err != nil { log.Error(). Str("handler", "ApplePlatformConfig"). Err(err). Msg("Could not render Apple platform template") c.Data(http.StatusInternalServerError, "text/html; charset=utf-8", []byte("Could not render Apple platform template")) return } c.Data(http.StatusOK, "application/x-apple-aspen-config; charset=utf-8", content.Bytes()) } type AppleMobileConfig struct { UUID uuid.UUID Url string Payload string } type AppleMobilePlatformConfig struct { UUID uuid.UUID Url string } var commonTemplate = template.Must(template.New("mobileconfig").Parse(` PayloadUUID {{.UUID}} PayloadDisplayName Headscale PayloadDescription Configure Tailscale login server to: {{.Url}} PayloadIdentifier com.github.juanfont.headscale PayloadRemovalDisallowed PayloadType Configuration PayloadVersion 1 PayloadContent {{.Payload}} `)) var iosTemplate = template.Must(template.New("iosTemplate").Parse(` PayloadType io.tailscale.ipn.ios PayloadUUID {{.UUID}} PayloadIdentifier com.github.juanfont.headscale PayloadVersion 1 PayloadEnabled ControlURL {{.Url}} `)) var macosTemplate = template.Must(template.New("macosTemplate").Parse(` PayloadType io.tailscale.ipn.macos PayloadUUID {{.UUID}} PayloadIdentifier com.github.juanfont.headscale PayloadVersion 1 PayloadEnabled ControlURL {{.Url}} `))