mirror of
https://github.com/micromdm/micromdm/
synced 2026-08-08 10:45:34 +08:00
refactor block service for HA (#349)
This commit is contained in:
@@ -205,7 +205,7 @@ func (cmd *applyCommand) applyBlock(args []string) error {
|
||||
flagset.Usage()
|
||||
return errors.New("bad input: must provide a device UDID to block.")
|
||||
}
|
||||
if err := cmd.applysvc.BlockDevice(context.Background(), *flUDID); err != nil {
|
||||
if err := cmd.blocksvc.BlockDevice(context.Background(), *flUDID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -24,7 +24,7 @@ func (cmd *removeCommand) removeBlock(args []string) error {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
if err := cmd.remove.UnblockDevice(ctx, *flUDID); err != nil {
|
||||
if err := cmd.blocksvc.UnblockDevice(ctx, *flUDID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ import (
|
||||
|
||||
"github.com/micromdm/micromdm/platform/api/server/apply"
|
||||
"github.com/micromdm/micromdm/platform/api/server/list"
|
||||
"github.com/micromdm/micromdm/platform/api/server/remove"
|
||||
"github.com/micromdm/micromdm/platform/blueprint"
|
||||
"github.com/micromdm/micromdm/platform/profile"
|
||||
"github.com/micromdm/micromdm/platform/remove"
|
||||
)
|
||||
|
||||
type remoteServices struct {
|
||||
profilesvc profile.Service
|
||||
blueprintsvc blueprint.Service
|
||||
blocksvc remove.Service
|
||||
applysvc apply.Service
|
||||
list list.Service
|
||||
remove remove.Service
|
||||
}
|
||||
|
||||
func setupClient(logger log.Logger) (*remoteServices, error) {
|
||||
@@ -39,6 +39,13 @@ func setupClient(logger log.Logger) (*remoteServices, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blocksvc, err := remove.NewHTTPClient(
|
||||
cfg.ServerURL, cfg.APIToken, logger,
|
||||
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
applysvc, err := apply.NewClient(
|
||||
cfg.ServerURL, logger, cfg.APIToken,
|
||||
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
|
||||
@@ -53,18 +60,11 @@ func setupClient(logger log.Logger) (*remoteServices, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rmsvc, err := remove.NewClient(
|
||||
cfg.ServerURL, logger, cfg.APIToken,
|
||||
httptransport.SetClient(skipVerifyHTTPClient(cfg.SkipVerify)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &remoteServices{
|
||||
profilesvc: profilesvc,
|
||||
blueprintsvc: blueprintsvc,
|
||||
blocksvc: blocksvc,
|
||||
applysvc: applysvc,
|
||||
list: listsvc,
|
||||
remove: rmsvc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import (
|
||||
"github.com/micromdm/micromdm/pkg/crypto"
|
||||
"github.com/micromdm/micromdm/platform/api/server/apply"
|
||||
"github.com/micromdm/micromdm/platform/api/server/list"
|
||||
"github.com/micromdm/micromdm/platform/api/server/remove"
|
||||
"github.com/micromdm/micromdm/platform/apns"
|
||||
"github.com/micromdm/micromdm/platform/appstore"
|
||||
"github.com/micromdm/micromdm/platform/blueprint"
|
||||
@@ -60,6 +59,7 @@ import (
|
||||
"github.com/micromdm/micromdm/platform/pubsub/inmem"
|
||||
"github.com/micromdm/micromdm/platform/queue"
|
||||
block "github.com/micromdm/micromdm/platform/remove"
|
||||
blockbuiltin "github.com/micromdm/micromdm/platform/remove/builtin"
|
||||
"github.com/micromdm/micromdm/platform/user"
|
||||
"github.com/micromdm/micromdm/workflow/webhook"
|
||||
)
|
||||
@@ -162,7 +162,7 @@ func serve(args []string) error {
|
||||
stdlog.Fatal(sm.err)
|
||||
}
|
||||
|
||||
removeService, err := block.NewService(sm.removeDB)
|
||||
removeService, err := block.New(sm.removeDB)
|
||||
if err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
@@ -285,6 +285,7 @@ func serve(args []string) error {
|
||||
|
||||
blueprintEndpoints := blueprint.MakeServerEndpoints(blueprintsvc)
|
||||
|
||||
blockEndpoints := block.MakeServerEndpoints(removeService)
|
||||
var listsvc list.Service
|
||||
{
|
||||
l := &list.ListService{
|
||||
@@ -318,11 +319,10 @@ func serve(args []string) error {
|
||||
var applysvc apply.Service
|
||||
{
|
||||
l := &apply.ApplyService{
|
||||
DEPClient: dc,
|
||||
Tokens: tokenDB,
|
||||
Apps: appDB,
|
||||
Users: userDB,
|
||||
RemoveService: removeService,
|
||||
DEPClient: dc,
|
||||
Tokens: tokenDB,
|
||||
Apps: appDB,
|
||||
Users: userDB,
|
||||
}
|
||||
applysvc = l
|
||||
if err := l.WatchTokenUpdates(sm.pubclient); err != nil {
|
||||
@@ -350,16 +350,12 @@ func serve(args []string) error {
|
||||
DefineDEPProfileEndpoint: defineDEPProfileEndpoint,
|
||||
AppUploadEndpoint: appUploadEndpoint,
|
||||
ApplyUserEndpoint: applyUserEndpoint,
|
||||
BlockDeviceEndpoint: apply.MakeBlockDeviceEndpoint(applysvc),
|
||||
}
|
||||
|
||||
applyAPIHandlers := apply.MakeHTTPHandlers(ctx, applyEndpoints, connectOpts...)
|
||||
|
||||
listAPIHandlers := list.MakeHTTPHandlers(ctx, listEndpoints, connectOpts...)
|
||||
|
||||
rmsvc := &remove.RemoveService{RemoveService: removeService}
|
||||
removeAPIHandlers := remove.MakeHTTPHandlers(ctx, remove.MakeEndpoints(rmsvc), connectOpts...)
|
||||
|
||||
connectHandlers := connect.MakeHTTPHandlers(ctx, connectEndpoints, connectOpts...)
|
||||
|
||||
scepHandler := scep.ServiceHandler(ctx, sm.scepService, httpLogger)
|
||||
@@ -378,16 +374,17 @@ func serve(args []string) error {
|
||||
|
||||
profilesHandler := profile.MakeHTTPHandler(profileEndpoints, logger)
|
||||
blueprintsHandler := blueprint.MakeHTTPHandler(blueprintEndpoints, logger)
|
||||
blockhandler := block.MakeHTTPHandler(blockEndpoints, logger)
|
||||
|
||||
// API commands. Only handled if the user provides an api key.
|
||||
if *flAPIKey != "" {
|
||||
r.Handle("/v1/profiles", apiAuthMiddleware(*flAPIKey, profilesHandler))
|
||||
r.Handle("/v1/blueprints", apiAuthMiddleware(*flAPIKey, blueprintsHandler))
|
||||
r.Handle("/v1/devices/{udid}/block", apiAuthMiddleware(*flAPIKey, blockhandler))
|
||||
r.Handle("/v1/devices/{udid}/unblock", apiAuthMiddleware(*flAPIKey, blockhandler))
|
||||
r.Handle("/push/{udid}", apiAuthMiddleware(*flAPIKey, pushHandlers.PushHandler))
|
||||
r.Handle("/v1/commands", apiAuthMiddleware(*flAPIKey, commandHandlers.NewCommandHandler)).Methods("POST")
|
||||
r.Handle("/v1/devices", apiAuthMiddleware(*flAPIKey, listAPIHandlers.ListDevicesHandler)).Methods("GET")
|
||||
r.Handle("/v1/devices/{udid}/block", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.BlockDeviceHandler)).Methods("POST")
|
||||
r.Handle("/v1/devices/{udid}/unblock", apiAuthMiddleware(*flAPIKey, removeAPIHandlers.UnblockDeviceHandler)).Methods("POST")
|
||||
r.Handle("/v1/dep-tokens", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetDEPTokensHandler)).Methods("GET")
|
||||
r.Handle("/v1/dep-tokens", apiAuthMiddleware(*flAPIKey, applyAPIHandlers.DEPTokensHandler)).Methods("PUT")
|
||||
r.Handle("/v1/dep/devices", apiAuthMiddleware(*flAPIKey, listAPIHandlers.GetDEPDeviceDetailsHandler)).Methods("GET")
|
||||
@@ -495,7 +492,7 @@ type server struct {
|
||||
scepDepot *boltdepot.Depot
|
||||
profileDB profile.Store
|
||||
configDB *config.DB
|
||||
removeDB *block.DB
|
||||
removeDB block.Store
|
||||
CommandWebhookURL string
|
||||
|
||||
// TODO: refactor enroll service and remove the need to reference
|
||||
@@ -564,7 +561,7 @@ func (c *server) setupRemoveService() {
|
||||
if c.err != nil {
|
||||
return
|
||||
}
|
||||
removeDB, err := block.NewDB(c.db)
|
||||
removeDB, err := blockbuiltin.NewDB(c.db)
|
||||
if err != nil {
|
||||
c.err = err
|
||||
return
|
||||
|
||||
@@ -60,23 +60,11 @@ func NewClient(instance string, logger log.Logger, token string, opts ...httptra
|
||||
).Endpoint()
|
||||
}
|
||||
|
||||
var blockDeviceEndpoint endpoint.Endpoint
|
||||
{
|
||||
blockDeviceEndpoint = httptransport.NewClient(
|
||||
"POST",
|
||||
copyURL(u, ""), // empty path, modified by the encodeRequest func
|
||||
encodeRequestWithToken(token, encodeBlockDeviceRequest),
|
||||
DecodeBlockDeviceResponse,
|
||||
opts...,
|
||||
).Endpoint()
|
||||
}
|
||||
|
||||
return Endpoints{
|
||||
ApplyDEPTokensEndpoint: applyDEPTokensEndpoint,
|
||||
DefineDEPProfileEndpoint: defineDEPProfileEndpoint,
|
||||
AppUploadEndpoint: uploadAppEndpoint,
|
||||
ApplyUserEndpoint: applyUserEndpoint,
|
||||
BlockDeviceEndpoint: blockDeviceEndpoint,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ type Endpoints struct {
|
||||
DefineDEPProfileEndpoint endpoint.Endpoint
|
||||
AppUploadEndpoint endpoint.Endpoint
|
||||
ApplyUserEndpoint endpoint.Endpoint
|
||||
BlockDeviceEndpoint endpoint.Endpoint
|
||||
}
|
||||
|
||||
func (e Endpoints) ApplyUser(ctx context.Context, u user.User) (*user.User, error) {
|
||||
@@ -30,17 +29,6 @@ func (e Endpoints) ApplyUser(ctx context.Context, u user.User) (*user.User, erro
|
||||
return &usr, resp.(applyUserResponse).Err
|
||||
}
|
||||
|
||||
func (e Endpoints) BlockDevice(ctx context.Context, udid string) error {
|
||||
request := blockDeviceRequest{
|
||||
UDID: udid,
|
||||
}
|
||||
resp, err := e.BlockDeviceEndpoint(ctx, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return resp.(blockDeviceResponse).Err
|
||||
}
|
||||
|
||||
func (e Endpoints) UploadApp(ctx context.Context, manifestName string, manifest io.Reader, pkgName string, pkg io.Reader) error {
|
||||
request := appUploadRequest{
|
||||
ManifestName: manifestName,
|
||||
@@ -116,16 +104,6 @@ func MakeUploadAppEndpiont(svc Service) endpoint.Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
func MakeBlockDeviceEndpoint(svc Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
||||
req := request.(blockDeviceRequest)
|
||||
err = svc.BlockDevice(ctx, req.UDID)
|
||||
return &blockDeviceResponse{
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type appUploadRequest struct {
|
||||
ManifestName string
|
||||
ManifestFile io.Reader
|
||||
@@ -168,13 +146,3 @@ type applyUserResponse struct {
|
||||
}
|
||||
|
||||
func (r applyUserResponse) error() error { return r.Err }
|
||||
|
||||
type blockDeviceRequest struct {
|
||||
UDID string
|
||||
}
|
||||
|
||||
type blockDeviceResponse struct {
|
||||
Err error `json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (r blockDeviceResponse) error() error { return r.Err }
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/micromdm/micromdm/platform/appstore"
|
||||
"github.com/micromdm/micromdm/platform/deptoken"
|
||||
"github.com/micromdm/micromdm/platform/pubsub"
|
||||
"github.com/micromdm/micromdm/platform/remove"
|
||||
"github.com/micromdm/micromdm/platform/user"
|
||||
)
|
||||
|
||||
@@ -28,7 +27,6 @@ type Service interface {
|
||||
UploadApp(ctx context.Context, manifestName string, manifest io.Reader, pkgName string, pkg io.Reader) error
|
||||
ApplyUser(ctx context.Context, u user.User) (*user.User, error)
|
||||
DEPService
|
||||
BlockDevice(ctx context.Context, udid string) error
|
||||
}
|
||||
|
||||
type ApplyService struct {
|
||||
@@ -38,7 +36,6 @@ type ApplyService struct {
|
||||
Tokens *deptoken.DB
|
||||
Apps appstore.AppStore
|
||||
Users *user.DB
|
||||
*remove.RemoveService
|
||||
}
|
||||
|
||||
func (svc *ApplyService) ApplyUser(ctx context.Context, u user.User) (*user.User, error) {
|
||||
|
||||
@@ -8,10 +8,8 @@ import (
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
httptransport "github.com/go-kit/kit/transport/http"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -20,7 +18,6 @@ type HTTPHandlers struct {
|
||||
DefineDEPProfileHandler http.Handler
|
||||
AppUploadHandler http.Handler
|
||||
ApplyUserhandler http.Handler
|
||||
BlockDeviceHandler http.Handler
|
||||
}
|
||||
|
||||
func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptransport.ServerOption) HTTPHandlers {
|
||||
@@ -49,28 +46,10 @@ func MakeHTTPHandlers(ctx context.Context, endpoints Endpoints, opts ...httptran
|
||||
encodeResponse,
|
||||
opts...,
|
||||
),
|
||||
BlockDeviceHandler: httptransport.NewServer(
|
||||
endpoints.BlockDeviceEndpoint,
|
||||
decodeBlockDeviceRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
),
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func decodeBlockDeviceRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var errBadRoute = errors.New("bad route")
|
||||
var req blockDeviceRequest
|
||||
vars := mux.Vars(r)
|
||||
udid, ok := vars["udid"]
|
||||
if !ok {
|
||||
return 0, errBadRoute
|
||||
}
|
||||
req.UDID = udid
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeDEPTokensRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var req depTokensRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -199,13 +178,6 @@ func EncodeHTTPGenericRequest(_ context.Context, r *http.Request, request interf
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeBlockDeviceRequest(_ context.Context, r *http.Request, request interface{}) error {
|
||||
req := request.(blockDeviceRequest)
|
||||
udid := url.QueryEscape(req.UDID)
|
||||
r.Method, r.URL.Path = "POST", "/v1/devices/"+udid+"/block"
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecodeDEPTokensResponse(_ context.Context, r *http.Response) (interface{}, error) {
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return nil, errorDecoder(r)
|
||||
@@ -241,12 +213,3 @@ func DecodeApplyUserResponse(_ context.Context, r *http.Response) (interface{},
|
||||
err := json.NewDecoder(r.Body).Decode(&resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func DecodeBlockDeviceResponse(_ context.Context, r *http.Response) (interface{}, error) {
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return nil, errorDecoder(r)
|
||||
}
|
||||
var resp blockDeviceResponse
|
||||
err := json.NewDecoder(r.Body).Decode(&resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
package remove
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
type Endpoints struct {
|
||||
UnblockDeviceEndpoint endpoint.Endpoint
|
||||
}
|
||||
|
||||
func MakeEndpoints(svc Service) Endpoints {
|
||||
e := Endpoints{
|
||||
UnblockDeviceEndpoint: MakeUnblockDeviceEndpoint(svc),
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e Endpoints) UnblockDevice(ctx context.Context, udid string) error {
|
||||
request := unblockDeviceRequest{UDID: udid}
|
||||
resp, err := e.UnblockDeviceEndpoint(ctx, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return resp.(unblockDeviceResponse).Err
|
||||
}
|
||||
|
||||
func MakeUnblockDeviceEndpoint(svc Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
||||
req := request.(unblockDeviceRequest)
|
||||
err = svc.UnblockDevice(ctx, req.UDID)
|
||||
return unblockDeviceResponse{
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type unblockDeviceRequest struct {
|
||||
UDID string
|
||||
}
|
||||
|
||||
type unblockDeviceResponse struct {
|
||||
Err error `json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (r unblockDeviceResponse) error() error { return r.Err }
|
||||
|
||||
type blueprintRequest struct {
|
||||
Names []string `json:"names"`
|
||||
}
|
||||
|
||||
type blueprintResponse struct {
|
||||
Err error `json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (r blueprintResponse) error() error { return r.Err }
|
||||
|
||||
type profileRequest struct {
|
||||
Identifiers []string `json:"ids"`
|
||||
}
|
||||
|
||||
type profileResponse struct {
|
||||
Err error `json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (r profileResponse) error() error { return r.Err }
|
||||
@@ -1,15 +0,0 @@
|
||||
package remove
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micromdm/micromdm/platform/remove"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
UnblockDevice(ctx context.Context, udid string) error
|
||||
}
|
||||
|
||||
type RemoveService struct {
|
||||
*remove.RemoveService
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package remove
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
httptransport "github.com/go-kit/kit/transport/http"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type HTTPHandlers struct {
|
||||
UnblockDeviceHandler http.Handler
|
||||
}
|
||||
|
||||
func MakeHTTPHandlers(ctx context.Context, endpoint Endpoints, opts ...httptransport.ServerOption) HTTPHandlers {
|
||||
h := HTTPHandlers{
|
||||
UnblockDeviceHandler: httptransport.NewServer(
|
||||
endpoint.UnblockDeviceEndpoint,
|
||||
decodeUnblockDeviceRequest,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
),
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func decodeUnblockDeviceRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var errBadRoute = errors.New("bad route")
|
||||
var req unblockDeviceRequest
|
||||
vars := mux.Vars(r)
|
||||
udid, ok := vars["udid"]
|
||||
if !ok {
|
||||
return 0, errBadRoute
|
||||
}
|
||||
req.UDID = udid
|
||||
return req, nil
|
||||
}
|
||||
|
||||
type errorWrapper struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type errorer interface {
|
||||
error() error
|
||||
}
|
||||
|
||||
func errorDecoder(r *http.Response) error {
|
||||
var w errorWrapper
|
||||
if err := json.NewDecoder(r.Body).Decode(&w); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New(w.Error)
|
||||
}
|
||||
|
||||
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
if e, ok := response.(errorer); ok && e.error() != nil {
|
||||
EncodeError(ctx, e.error(), w)
|
||||
return nil
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(response)
|
||||
}
|
||||
|
||||
func EncodeError(ctx context.Context, err error, w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
enc.Encode(errorWrapper{Error: err.Error()})
|
||||
}
|
||||
|
||||
// EncodeHTTPGenericRequest is a transport/http.EncodeRequestFunc that
|
||||
// JSON-encodes any request to the request body. Primarily useful in a client.
|
||||
func EncodeHTTPGenericRequest(_ context.Context, r *http.Request, request interface{}) error {
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(request); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Body = ioutil.NopCloser(&buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeUnblockDeviceRequest(_ context.Context, r *http.Request, request interface{}) error {
|
||||
req := request.(unblockDeviceRequest)
|
||||
udid := url.QueryEscape(req.UDID)
|
||||
r.Method, r.URL.Path = "POST", "/v1/devices/"+udid+"/unblock"
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecodeUnblockDeviceResponse(_ context.Context, r *http.Response) (interface{}, error) {
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return nil, errorDecoder(r)
|
||||
}
|
||||
var resp unblockDeviceResponse
|
||||
err := json.NewDecoder(r.Body).Decode(&resp)
|
||||
return resp, err
|
||||
}
|
||||
75
platform/remove/block_device.go
Normal file
75
platform/remove/block_device.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package remove
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (svc *RemoveService) BlockDevice(ctx context.Context, udid string) error {
|
||||
return svc.store.Save(&Device{UDID: udid})
|
||||
}
|
||||
|
||||
type blockDeviceRequest struct {
|
||||
UDID string
|
||||
}
|
||||
|
||||
type blockDeviceResponse struct {
|
||||
Err error `json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (r blockDeviceResponse) error() error { return r.Err }
|
||||
|
||||
func decodeBlockDeviceRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var errBadRoute = errors.New("bad route")
|
||||
var req blockDeviceRequest
|
||||
vars := mux.Vars(r)
|
||||
udid, ok := vars["udid"]
|
||||
if !ok {
|
||||
return 0, errBadRoute
|
||||
}
|
||||
req.UDID = udid
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeBlockDeviceRequest(_ context.Context, r *http.Request, request interface{}) error {
|
||||
req := request.(blockDeviceRequest)
|
||||
udid := url.QueryEscape(req.UDID)
|
||||
r.Method, r.URL.Path = "POST", "/v1/devices/"+udid+"/block"
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeBlockDeviceResponse(_ context.Context, r *http.Response) (interface{}, error) {
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return nil, errorDecoder(r)
|
||||
}
|
||||
var resp blockDeviceResponse
|
||||
err := json.NewDecoder(r.Body).Decode(&resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func MakeBlockDeviceEndpoint(svc Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
||||
req := request.(blockDeviceRequest)
|
||||
err = svc.BlockDevice(ctx, req.UDID)
|
||||
return &blockDeviceResponse{
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e Endpoints) BlockDevice(ctx context.Context, udid string) error {
|
||||
request := blockDeviceRequest{
|
||||
UDID: udid,
|
||||
}
|
||||
resp, err := e.BlockDeviceEndpoint(ctx, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return resp.(blockDeviceResponse).Err
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package remove
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/micromdm/micromdm/platform/remove"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -27,20 +28,20 @@ func NewDB(db *bolt.DB) (*DB, error) {
|
||||
return datastore, nil
|
||||
}
|
||||
|
||||
func (db *DB) DeviceByUDID(udid string) (*Device, error) {
|
||||
var dev Device
|
||||
func (db *DB) DeviceByUDID(udid string) (*remove.Device, error) {
|
||||
var dev remove.Device
|
||||
err := db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(RemoveBucket))
|
||||
v := b.Get([]byte(udid))
|
||||
if v == nil {
|
||||
return ¬Found{"Device", fmt.Sprintf("udid %s", udid)}
|
||||
}
|
||||
return UnmarshalDevice(v, &dev)
|
||||
return remove.UnmarshalDevice(v, &dev)
|
||||
})
|
||||
return &dev, errors.Wrap(err, "remove: get device by udid")
|
||||
}
|
||||
|
||||
func (db *DB) Save(dev *Device) error {
|
||||
func (db *DB) Save(dev *remove.Device) error {
|
||||
tx, err := db.DB.Begin(true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "begin transaction")
|
||||
@@ -49,7 +50,7 @@ func (db *DB) Save(dev *Device) error {
|
||||
if bkt == nil {
|
||||
return fmt.Errorf("bucket %q not found!", RemoveBucket)
|
||||
}
|
||||
pb, err := MarshalDevice(dev)
|
||||
pb, err := remove.MarshalDevice(dev)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "marshalling Device")
|
||||
}
|
||||
@@ -81,10 +82,6 @@ func (e *notFound) Error() string {
|
||||
return fmt.Sprintf("not found: %s %s", e.ResourceType, e.Message)
|
||||
}
|
||||
|
||||
func isNotFound(err error) bool {
|
||||
cause := errors.Cause(err)
|
||||
if _, ok := cause.(*notFound); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
func (e *notFound) NotFound() bool {
|
||||
return true
|
||||
}
|
||||
@@ -10,24 +10,36 @@ import (
|
||||
httptransport "github.com/go-kit/kit/transport/http"
|
||||
)
|
||||
|
||||
func NewClient(instance string, logger log.Logger, token string, opts ...httptransport.ClientOption) (Service, error) {
|
||||
func NewHTTPClient(instance, token string, logger log.Logger, opts ...httptransport.ClientOption) (Service, error) {
|
||||
u, err := url.Parse(instance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var blockDeviceEndpoint endpoint.Endpoint
|
||||
{
|
||||
blockDeviceEndpoint = httptransport.NewClient(
|
||||
"POST",
|
||||
copyURL(u, ""), // empty path, modified by the encodeRequest func
|
||||
encodeRequestWithToken(token, encodeBlockDeviceRequest),
|
||||
decodeBlockDeviceResponse,
|
||||
opts...,
|
||||
).Endpoint()
|
||||
}
|
||||
|
||||
var unblockDeviceEndpoint endpoint.Endpoint
|
||||
{
|
||||
unblockDeviceEndpoint = httptransport.NewClient(
|
||||
"POST",
|
||||
copyURL(u, ""), //modified by encodeRequestFunc
|
||||
encodeRequestWithToken(token, encodeUnblockDeviceRequest),
|
||||
DecodeUnblockDeviceResponse,
|
||||
decodeUnblockDeviceResponse,
|
||||
opts...,
|
||||
).Endpoint()
|
||||
}
|
||||
|
||||
return Endpoints{
|
||||
BlockDeviceEndpoint: blockDeviceEndpoint,
|
||||
UnblockDeviceEndpoint: unblockDeviceEndpoint,
|
||||
}, nil
|
||||
}
|
||||
@@ -10,27 +10,6 @@ import (
|
||||
"github.com/micromdm/micromdm/platform/remove/internal/removeproto"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
BlockDevice(ctx context.Context, udid string) error
|
||||
UnblockDevice(ctx context.Context, udid string) error
|
||||
}
|
||||
|
||||
type RemoveService struct {
|
||||
db *DB
|
||||
}
|
||||
|
||||
func NewService(db *DB) (*RemoveService, error) {
|
||||
return &RemoveService{db: db}, nil
|
||||
}
|
||||
|
||||
func (svc *RemoveService) BlockDevice(ctx context.Context, udid string) error {
|
||||
return svc.db.Save(&Device{UDID: udid})
|
||||
}
|
||||
|
||||
func (svc *RemoveService) UnblockDevice(ctx context.Context, udid string) error {
|
||||
return svc.db.Delete(udid)
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
UDID string `json:"udid"`
|
||||
}
|
||||
@@ -51,23 +30,23 @@ func UnmarshalDevice(data []byte, dev *Device) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveMiddleware(db *DB) connect.Middleware {
|
||||
func RemoveMiddleware(store Store) connect.Middleware {
|
||||
return func(next connect.Service) connect.Service {
|
||||
return &removeMiddleware{
|
||||
db: db,
|
||||
next: next,
|
||||
store: store,
|
||||
next: next,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type removeMiddleware struct {
|
||||
db *DB
|
||||
next connect.Service
|
||||
store Store
|
||||
next connect.Service
|
||||
}
|
||||
|
||||
func (mw removeMiddleware) Acknowledge(ctx context.Context, req connect.MDMConnectRequest) ([]byte, error) {
|
||||
udid := req.MDMResponse.UDID
|
||||
_, err := mw.db.DeviceByUDID(udid)
|
||||
_, err := mw.store.DeviceByUDID(udid)
|
||||
if err != nil {
|
||||
if !isNotFound(err) {
|
||||
return nil, errors.Wrapf(err, "remove: get device by udid %s", udid)
|
||||
@@ -88,3 +67,13 @@ func (checkoutErr) Error() string {
|
||||
func (checkoutErr) Checkout() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func isNotFound(err error) bool {
|
||||
type notFoundError interface {
|
||||
error
|
||||
NotFound() bool
|
||||
}
|
||||
|
||||
_, ok := err.(notFoundError)
|
||||
return ok
|
||||
}
|
||||
|
||||
68
platform/remove/server.go
Normal file
68
platform/remove/server.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package remove
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/go-kit/kit/log"
|
||||
httptransport "github.com/go-kit/kit/transport/http"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Endpoints struct {
|
||||
BlockDeviceEndpoint endpoint.Endpoint
|
||||
UnblockDeviceEndpoint endpoint.Endpoint
|
||||
}
|
||||
|
||||
func MakeServerEndpoints(s Service) Endpoints {
|
||||
return Endpoints{
|
||||
BlockDeviceEndpoint: MakeBlockDeviceEndpoint(s),
|
||||
UnblockDeviceEndpoint: MakeUnblockDeviceEndpoint(s),
|
||||
}
|
||||
}
|
||||
|
||||
func MakeHTTPHandler(e Endpoints, logger log.Logger) http.Handler {
|
||||
options := []httptransport.ServerOption{
|
||||
httptransport.ServerErrorLogger(logger),
|
||||
}
|
||||
|
||||
r := mux.NewRouter()
|
||||
|
||||
// POST /v1/devices/:udid/block force a device to unenroll next time it connects
|
||||
// POST /v1/devices/:udid/unblock allow a blocked device to enroll again
|
||||
|
||||
r.Methods("POST").Path("/v1/devices/{udid}/block").Handler(httptransport.NewServer(
|
||||
e.BlockDeviceEndpoint,
|
||||
decodeBlockDeviceRequest,
|
||||
httptransport.EncodeJSONResponse,
|
||||
options...,
|
||||
))
|
||||
|
||||
r.Methods("POST").Path("/v1/devices/{udid}/unblock").Handler(httptransport.NewServer(
|
||||
e.UnblockDeviceEndpoint,
|
||||
decodeUnblockDeviceRequest,
|
||||
httptransport.EncodeJSONResponse,
|
||||
options...,
|
||||
))
|
||||
|
||||
return r
|
||||
|
||||
}
|
||||
|
||||
type errorWrapper struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type errorer interface {
|
||||
error() error
|
||||
}
|
||||
|
||||
func errorDecoder(r *http.Response) error {
|
||||
var w errorWrapper
|
||||
if err := json.NewDecoder(r.Body).Decode(&w); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New(w.Error)
|
||||
}
|
||||
22
platform/remove/service.go
Normal file
22
platform/remove/service.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package remove
|
||||
|
||||
import "context"
|
||||
|
||||
type Service interface {
|
||||
BlockDevice(ctx context.Context, udid string) error
|
||||
UnblockDevice(ctx context.Context, udid string) error
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
Save(*Device) error
|
||||
DeviceByUDID(string) (*Device, error)
|
||||
Delete(string) error
|
||||
}
|
||||
|
||||
type RemoveService struct {
|
||||
store Store
|
||||
}
|
||||
|
||||
func New(store Store) (*RemoveService, error) {
|
||||
return &RemoveService{store: store}, nil
|
||||
}
|
||||
73
platform/remove/unblock_device.go
Normal file
73
platform/remove/unblock_device.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package remove
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (svc *RemoveService) UnblockDevice(ctx context.Context, udid string) error {
|
||||
return svc.store.Delete(udid)
|
||||
}
|
||||
|
||||
type unblockDeviceRequest struct {
|
||||
UDID string
|
||||
}
|
||||
|
||||
type unblockDeviceResponse struct {
|
||||
Err error `json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (r unblockDeviceResponse) error() error { return r.Err }
|
||||
|
||||
func decodeUnblockDeviceRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var errBadRoute = errors.New("bad route")
|
||||
var req unblockDeviceRequest
|
||||
vars := mux.Vars(r)
|
||||
udid, ok := vars["udid"]
|
||||
if !ok {
|
||||
return 0, errBadRoute
|
||||
}
|
||||
req.UDID = udid
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeUnblockDeviceRequest(_ context.Context, r *http.Request, request interface{}) error {
|
||||
req := request.(unblockDeviceRequest)
|
||||
udid := url.QueryEscape(req.UDID)
|
||||
r.Method, r.URL.Path = "POST", "/v1/devices/"+udid+"/unblock"
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUnblockDeviceResponse(_ context.Context, r *http.Response) (interface{}, error) {
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return nil, errorDecoder(r)
|
||||
}
|
||||
var resp unblockDeviceResponse
|
||||
err := json.NewDecoder(r.Body).Decode(&resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func MakeUnblockDeviceEndpoint(svc Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
||||
req := request.(unblockDeviceRequest)
|
||||
err = svc.UnblockDevice(ctx, req.UDID)
|
||||
return unblockDeviceResponse{
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e Endpoints) UnblockDevice(ctx context.Context, udid string) error {
|
||||
request := unblockDeviceRequest{UDID: udid}
|
||||
resp, err := e.UnblockDeviceEndpoint(ctx, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return resp.(unblockDeviceResponse).Err
|
||||
}
|
||||
Reference in New Issue
Block a user