mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 08:28:52 +00:00
relates to #21559 This adds the ability for end users to enrol their own device in fleet mdm. > NOTE: this new byod HTML page is a separate HTML asset that contains all styles and scripts needed for the page to work. We do not send the fleet UI assets and this drastically cuts down the response time to the users who will be visiting this page on mobile devices There are two sides included in this: **Adding a new add host modal ios and iPad section for IT admins**  **delivering a new byod HTML page to end users that will allow end users to download the config profile to enrol into fleet mdm**  <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [ ] Added/updated tests - [x] Manual QA for all new/changed functionality
138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
assetfs "github.com/elazarl/go-bindata-assetfs"
|
|
"github.com/fleetdm/fleet/v4/server/bindata"
|
|
"github.com/go-kit/log"
|
|
)
|
|
|
|
func newBinaryFileSystem(root string) *assetfs.AssetFS {
|
|
return &assetfs.AssetFS{
|
|
Asset: bindata.Asset,
|
|
AssetDir: bindata.AssetDir,
|
|
AssetInfo: bindata.AssetInfo,
|
|
Prefix: root,
|
|
}
|
|
}
|
|
|
|
func ServeFrontend(urlPrefix string, sandbox bool, logger log.Logger) http.Handler {
|
|
herr := func(w http.ResponseWriter, err string) {
|
|
logger.Log("err", err)
|
|
http.Error(w, err, http.StatusInternalServerError)
|
|
}
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
writeBrowserSecurityHeaders(w)
|
|
|
|
// The following check is to prevent a misconfigured osquery from submitting
|
|
// data to the root endpoint (the osquery remote API uses POST for all its endpoints).
|
|
// See https://github.com/fleetdm/fleet/issues/16182.
|
|
if r.Method == "POST" {
|
|
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
fs := newBinaryFileSystem("/frontend")
|
|
file, err := fs.Open("templates/react.tmpl")
|
|
if err != nil {
|
|
herr(w, "load react template: "+err.Error())
|
|
return
|
|
}
|
|
data, err := io.ReadAll(file)
|
|
if err != nil {
|
|
herr(w, "read bindata file: "+err.Error())
|
|
return
|
|
}
|
|
t, err := template.New("react").Parse(string(data))
|
|
if err != nil {
|
|
herr(w, "create react template: "+err.Error())
|
|
return
|
|
}
|
|
serverType := "on-premise"
|
|
if sandbox {
|
|
serverType = "sandbox"
|
|
}
|
|
if err := t.Execute(w, struct {
|
|
URLPrefix string
|
|
ServerType string
|
|
}{
|
|
URLPrefix: urlPrefix,
|
|
ServerType: serverType,
|
|
}); err != nil {
|
|
herr(w, "execute react template: "+err.Error())
|
|
return
|
|
}
|
|
})
|
|
}
|
|
|
|
func ServeEndUserEnrollOTA(urlPrefix string, logger log.Logger) http.Handler {
|
|
herr := func(w http.ResponseWriter, err string) {
|
|
logger.Log("err", err)
|
|
http.Error(w, err, http.StatusInternalServerError)
|
|
}
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
writeBrowserSecurityHeaders(w)
|
|
|
|
fs := newBinaryFileSystem("/frontend")
|
|
file, err := fs.Open("templates/enroll-ota.html")
|
|
if err != nil {
|
|
herr(w, "load enroll ota template: "+err.Error())
|
|
return
|
|
}
|
|
|
|
data, err := io.ReadAll(file)
|
|
if err != nil {
|
|
herr(w, "read bindata file: "+err.Error())
|
|
return
|
|
}
|
|
|
|
t, err := template.New("enroll-ota").Parse(string(data))
|
|
if err != nil {
|
|
herr(w, "create react template: "+err.Error())
|
|
return
|
|
}
|
|
|
|
enrollURL, err := generateEnrollOTAURL(urlPrefix, r.URL.Query().Get("enroll_secret"))
|
|
if err != nil {
|
|
herr(w, "generate enroll ota url: "+err.Error())
|
|
return
|
|
}
|
|
if err := t.Execute(w, struct {
|
|
EnrollURL string
|
|
URLPrefix string
|
|
}{
|
|
URLPrefix: urlPrefix,
|
|
EnrollURL: enrollURL,
|
|
}); err != nil {
|
|
herr(w, "execute react template: "+err.Error())
|
|
return
|
|
}
|
|
})
|
|
}
|
|
|
|
func generateEnrollOTAURL(fleetURL string, enrollSecret string) (string, error) {
|
|
path, err := url.JoinPath(fleetURL, "/api/v1/fleet/enrollment_profiles/ota")
|
|
if err != nil {
|
|
return "", fmt.Errorf("creating path for end user ota enrollment url: %w", err)
|
|
}
|
|
|
|
enrollURL, err := url.Parse(path)
|
|
if err != nil {
|
|
return "", fmt.Errorf("parsing end user ota enrollment url: %w", err)
|
|
}
|
|
|
|
q := enrollURL.Query()
|
|
q.Set("enroll_secret", enrollSecret)
|
|
enrollURL.RawQuery = q.Encode()
|
|
return enrollURL.String(), nil
|
|
}
|
|
|
|
func ServeStaticAssets(path string) http.Handler {
|
|
return http.StripPrefix(path, http.FileServer(newBinaryFileSystem("/assets")))
|
|
}
|