diff --git a/apple_mobileconfig.go b/apple_mobileconfig.go new file mode 100644 index 00000000..cfaffa06 --- /dev/null +++ b/apple_mobileconfig.go @@ -0,0 +1,179 @@ +package headscale + +import ( + "bytes" + "net/http" + "text/template" + + "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 { + c.Error(err) + 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 { + c.Error(err) + return + } + + contentId, err := uuid.NewV4() + if err != nil { + c.Error(err) + 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 { + c.Error(err) + return + } + case "ios": + if err := iosTemplate.Execute(&payload, platformConfig); err != nil { + c.Error(err) + 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 { + c.Error(err) + 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}} + +`)) diff --git a/go.mod b/go.mod index 0d8c86b5..88c314f6 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.16 require ( github.com/AlecAivazis/survey/v2 v2.0.5 github.com/gin-gonic/gin v1.7.2 + github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b github.com/klauspost/compress v1.13.1 github.com/lib/pq v1.10.2 // indirect diff --git a/go.sum b/go.sum index 4751eaac..88cb0773 100644 --- a/go.sum +++ b/go.sum @@ -219,6 +219,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=