fleet/server/service/installer.go
Roberto Dip 90b723e45a
consolidate sandbox env flags (#6917)
Related to #6894, this entirely replaces FLEET_DEMO with the server config added in #6597

As part of this, I also implemented a small refactor to the integration test suite to allow setting a custom config when the server is initialized.
2022-07-27 16:47:39 -03:00

93 lines
2.8 KiB
Go

package service
import (
"context"
"errors"
"io"
"net/http"
"strconv"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/contexts/logging"
"github.com/fleetdm/fleet/v4/server/fleet"
)
type installerRequest struct {
EnrollSecret string `url:"enroll_secret"`
Kind string `url:"kind"`
Desktop bool `query:"desktop,optional"`
}
////////////////////////////////////////////////////////////////////////////////
// Retrieve an Orbit installer from storage
////////////////////////////////////////////////////////////////////////////////
type getInstallerResponse struct {
Err error `json:"error,omitempty"`
// file fields below are used in hijackRender for the response
fileReader io.ReadCloser
fileLength int64
}
func (r getInstallerResponse) error() error { return r.Err }
func (r getInstallerResponse) hijackRender(ctx context.Context, w http.ResponseWriter) {
w.Header().Set("Content-Length", strconv.FormatInt(r.fileLength, 10))
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment")
// OK to just log the error here as writing anything on
// `http.ResponseWriter` sets the status code to 200 (and it can't be
// changed.) Clients should rely on matching content-length with the
// header provided
wl, err := io.Copy(w, r.fileReader)
if err != nil {
logging.WithExtras(ctx, "s3_copy_error", err, "bytes_copied", wl)
}
r.fileReader.Close()
}
func getInstallerEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
req := request.(*installerRequest)
fileReader, fileLength, err := svc.GetInstaller(ctx, fleet.Installer{
EnrollSecret: req.EnrollSecret,
Kind: req.Kind,
Desktop: req.Desktop,
})
if err != nil {
return getInstallerResponse{Err: err}, nil
}
return getInstallerResponse{fileReader: fileReader, fileLength: fileLength}, nil
}
// GetInstaller retrieves a blob containing the installer binary
func (svc *Service) GetInstaller(ctx context.Context, installer fleet.Installer) (io.ReadCloser, int64, error) {
if err := svc.authz.Authorize(ctx, &fleet.EnrollSecret{}, fleet.ActionRead); err != nil {
return nil, int64(0), err
}
if !svc.SandboxEnabled() {
return nil, int64(0), errors.New("this endpoint only enabled in demo mode")
}
if svc.installerStore == nil {
return nil, int64(0), ctxerr.New(ctx, "installer storage has not been configured")
}
_, err := svc.ds.VerifyEnrollSecret(ctx, installer.EnrollSecret)
if err != nil {
return nil, int64(0), ctxerr.Wrap(ctx, err, "finding a matching enroll secret")
}
reader, length, err := svc.installerStore.Get(ctx, installer)
if err != nil {
return nil, int64(0), ctxerr.Wrap(ctx, err, "unable to retrieve installer from store")
}
return reader, length, nil
}