Skip to content

Commit

Permalink
clean up, docs, minor refactor(s) 🧹 (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
jessepeterson authored Aug 1, 2023
1 parent 60d9089 commit 8c6c5ab
Show file tree
Hide file tree
Showing 39 changed files with 1,494 additions and 460 deletions.
71 changes: 39 additions & 32 deletions cmd/kmfddm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import (
httpddm "github.com/jessepeterson/kmfddm/http"
apihttp "github.com/jessepeterson/kmfddm/http/api"
ddmhttp "github.com/jessepeterson/kmfddm/http/ddm"
"github.com/jessepeterson/kmfddm/log/logkeys"
"github.com/jessepeterson/kmfddm/log/stdlogfmt"
"github.com/jessepeterson/kmfddm/notifier"
"github.com/jessepeterson/kmfddm/notifier/foss"
)

// overridden by -ldflags -X
Expand Down Expand Up @@ -51,24 +53,29 @@ func main() {
logger := stdlogfmt.New(stdlogfmt.WithDebugFlag(*flDebug))

if *flAPIKey == "" {
logger.Info("msg", "empty API key; API disabled")
logger.Info(logkeys.Message, "empty API key; API disabled")
}

storage, err := setupStorage(*flStorage, *flDSN)
if err != nil {
logger.Info("msg", "init storage", "name", *flStorage, "err", err)
logger.Info(logkeys.Message, "init storage", "name", *flStorage, logkeys.Error, err)
os.Exit(1)
}

nOpts := []notifier.Option{
notifier.WithLogger(logger.With("service", "notifier")),
nOpts := []foss.Option{
foss.WithLogger(logger.With("service", "notifier-foss")),
}
if *flMicro {
nOpts = append(nOpts, notifier.WithMicroMDM())
nOpts = append(nOpts, foss.WithMicroMDM())
}
nanoNotif, err := notifier.New(storage, *flEnqueueURL, *flEnqueueKey, nOpts...)
fossNotif, err := foss.NewFossMDM(*flEnqueueURL, *flEnqueueKey, nOpts...)
if err != nil {
logger.Info("msg", "creating notifier", "err", err)
logger.Info(logkeys.Message, "creating notifier", logkeys.Error, err)
os.Exit(1)
}
nanoNotif, err := notifier.New(fossNotif, storage, notifier.WithLogger(logger.With("service", "notifier")))
if err != nil {
logger.Info(logkeys.Message, "creating notifier", logkeys.Error, err)
os.Exit(1)
}

Expand All @@ -78,34 +85,34 @@ func main() {

mux.Handle(
"/declaration-items",
ddmhttp.TokensDeclarationItemsHandler(storage, false, logger.With("handler", "declaration-items")),
ddmhttp.TokensOrDeclarationItemsHandler(storage, false, logger.With(logkeys.Handler, "declaration-items")),
"GET",
)

mux.Handle(
"/tokens",
ddmhttp.TokensDeclarationItemsHandler(storage, true, logger.With("handler", "tokens")),
ddmhttp.TokensOrDeclarationItemsHandler(storage, true, logger.With(logkeys.Handler, "tokens")),
"GET",
)

mux.Handle(
"/declaration/:type/:id",
http.StripPrefix("/declaration/",
ddmhttp.DeclarationHandler(storage, logger.With("handler", "declaration")),
ddmhttp.DeclarationHandler(storage, logger.With(logkeys.Handler, "declaration")),
),
"GET",
)

var statusHandler http.Handler = ddmhttp.StatusReportHandler(storage, logger.With("handler", "status"))
var statusHandler http.Handler = ddmhttp.StatusReportHandler(storage, logger.With(logkeys.Handler, "status"))
if *flDumpStatus != "" {
f := os.Stdout
if *flDumpStatus != "-" {
if f, err = os.OpenFile(*flDumpStatus, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644); err != nil {
logger.Info("msg", "dump status", "path", *flDumpStatus, "err", err)
logger.Info(logkeys.Message, "dump status", "path", *flDumpStatus, logkeys.Error, err)
os.Exit(1)
}
defer f.Close()
logger.Debug("msg", "dump status", "path", *flDumpStatus)
logger.Debug(logkeys.Message, "dump status", "path", *flDumpStatus)
}
statusHandler = DumpHandler(statusHandler, f)
}
Expand Down Expand Up @@ -134,25 +141,25 @@ func main() {

mux.Handle(
"/v1/declarations",
apihttp.PutDeclarationHandler(storage, nanoNotif, logger.With("handler", "put-declaration")),
apihttp.PutDeclarationHandler(storage, nanoNotif, logger.With(logkeys.Handler, "put-declaration")),
"PUT",
)

mux.Handle(
"/v1/declarations/:id",
apihttp.GetDeclarationHandler(storage, logger.With("handler", "get-declaration")),
apihttp.GetDeclarationHandler(storage, logger.With(logkeys.Handler, "get-declaration")),
"GET",
)

mux.Handle(
"/v1/declarations/:id",
apihttp.DeleteDeclarationHandler(storage, logger.With("handler", "delete-declaration")),
apihttp.DeleteDeclarationHandler(storage, logger.With(logkeys.Handler, "delete-declaration")),
"DELETE",
)

mux.Handle(
"/v1/declarations/:id/touch",
apihttp.TouchDeclarationHandler(storage, nanoNotif, logger.With("handler", "touch-declaration")),
apihttp.TouchDeclarationHandler(storage, nanoNotif, logger.With(logkeys.Handler, "touch-declaration")),
"POST",
)

Expand All @@ -166,71 +173,71 @@ func main() {
// set declarations
mux.Handle(
"/v1/set-declarations/:id",
apihttp.GetSetDeclarationsHandler(storage, logger.With("handler", "get-set-declarations")),
apihttp.GetSetDeclarationsHandler(storage, logger.With(logkeys.Handler, "get-set-declarations")),
"GET",
)

mux.Handle(
"/v1/set-declarations/:id",
apihttp.PutSetDeclarationHandler(storage, nanoNotif, logger.With("handler", "put-set-declarations")),
apihttp.PutSetDeclarationHandler(storage, nanoNotif, logger.With(logkeys.Handler, "put-set-declarations")),
"PUT",
)

mux.Handle(
"/v1/set-declarations/:id",
apihttp.DeleteSetDeclarationHandler(storage, nanoNotif, logger.With("handler", "delete-set-delcarations")),
apihttp.DeleteSetDeclarationHandler(storage, nanoNotif, logger.With(logkeys.Handler, "delete-set-delcarations")),
"DELETE",
)

// enrollment sets
mux.Handle(
"/v1/enrollment-sets/:id",
apihttp.GetEnrollmentSetsHandler(storage, logger.With("handler", "get-enrollment-sets")),
apihttp.GetEnrollmentSetsHandler(storage, logger.With(logkeys.Handler, "get-enrollment-sets")),
"GET",
)

mux.Handle(
"/v1/enrollment-sets/:id",
apihttp.PutEnrollmentSetHandler(storage, nanoNotif, logger.With("handler", "put-enrollment-sets")),
apihttp.PutEnrollmentSetHandler(storage, nanoNotif, logger.With(logkeys.Handler, "put-enrollment-sets")),
"PUT",
)

mux.Handle(
"/v1/enrollment-sets/:id",
apihttp.DeleteEnrollmentSetHandler(storage, nanoNotif, logger.With("handler", "delete-enrollment-sets")),
apihttp.DeleteEnrollmentSetHandler(storage, nanoNotif, logger.With(logkeys.Handler, "delete-enrollment-sets")),
"DELETE",
)

// declarations sets
mux.Handle(
"/v1/declaration-sets/:id",
apihttp.GetDeclarationSetsHandler(storage, logger.With("handler", "get-declaration-sets")),
apihttp.GetDeclarationSetsHandler(storage, logger.With(logkeys.Handler, "get-declaration-sets")),
"GET",
)

// status queries
mux.Handle(
"/v1/declaration-status/:id",
apihttp.GetDeclarationStatusHandler(storage, logger.With("handler", "get-declaration-status")),
apihttp.GetDeclarationStatusHandler(storage, logger.With(logkeys.Handler, "get-declaration-status")),
"GET",
)

mux.Handle(
"/v1/status-errors/:id",
apihttp.GetStatusErrorsHandler(storage, logger.With("handler", "get-status-errors")),
apihttp.GetStatusErrorsHandler(storage, logger.With(logkeys.Handler, "get-status-errors")),
"GET",
)

mux.Handle(
"/v1/status-values/:id",
apihttp.GetStatusValuesHandler(storage, logger.With("handler", "get-status-values")),
apihttp.GetStatusValuesHandler(storage, logger.With(logkeys.Handler, "get-status-values")),
"GET",
)

// notifier
mux.Handle(
"/v1/notify",
apihttp.NotifyHandler(nanoNotif, logger.With("handler", "notify")),
apihttp.NotifyHandler(nanoNotif, logger.With(logkeys.Handler, "notify")),
"POST",
)
})
Expand All @@ -239,11 +246,11 @@ func main() {
// init for newTraceID()
rand.Seed(time.Now().UnixNano())

logger.Info("msg", "starting server", "listen", *flListen)
err = http.ListenAndServe(*flListen, httpddm.TraceLoggingMiddleware(mux, logger.With("handler", "log"), newTraceID))
logs := []interface{}{"msg", "server shutdown"}
logger.Info(logkeys.Message, "starting server", "listen", *flListen)
err = http.ListenAndServe(*flListen, httpddm.TraceLoggingMiddleware(mux, logger.With(logkeys.Handler, "log"), newTraceID))
logs := []interface{}{logkeys.Message, "server shutdown"}
if err != nil {
logs = append(logs, "err", err)
logs = append(logs, logkeys.Error, err)
}
logger.Info(logs...)
}
Expand Down
12 changes: 5 additions & 7 deletions cmd/kmfddm/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"hash"

"github.com/cespare/xxhash"
"github.com/jessepeterson/kmfddm/http/api"
"github.com/jessepeterson/kmfddm/http/ddm"
"github.com/jessepeterson/kmfddm/storage"
"github.com/jessepeterson/kmfddm/storage/file"
"github.com/jessepeterson/kmfddm/storage/mysql"
Expand All @@ -15,14 +13,14 @@ import (
)

type allStorage interface {
api.SetAPIStorage
api.DeclarationAPIStorage
ddm.StatusStorage
api.EnrollmentAPIStorage
api.StatusAPIStorage
storage.DeclarationAPIStorage
storage.EnrollmentIDRetriever
storage.EnrollmentDeclarationStorage
storage.StatusStorer
storage.SetDeclarationStorage
storage.SetRetreiver
storage.EnrollmentSetStorage
storage.StatusAPIStorage
}

var hasher func() hash.Hash = func() hash.Hash { return xxhash.New() }
Expand Down
5 changes: 4 additions & 1 deletion ddm/declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/valyala/fastjson"
)

var ErrInvalidDeclaration = errors.New("invalid declaration")

type Declaration struct {
Identifier string
Type string
Expand All @@ -33,7 +35,7 @@ func (d *Declaration) Valid() bool {
return true
}

// findIDRefs traverses the payload using IDRefs to find any dependent declarations.
// findIDRefs traverses the payload using IdentifierRefs to find any dependent declarations.
func findIDRefs(v *fastjson.Value, declarationType string) []string {
if _, ok := IdentifierRefs[declarationType]; !ok {
return nil
Expand Down Expand Up @@ -96,6 +98,7 @@ func parseDeclarationValue(v *fastjson.Value, d *Declaration) error {
return nil
}

// ParseDeclaration parses raw into a Declaration structure.
func ParseDeclaration(raw []byte) (*Declaration, error) {
v, err := fastjson.ParseBytes(raw)
if err != nil {
Expand Down
49 changes: 34 additions & 15 deletions ddm/items.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"strings"
)

// ManifestDeclaration contains the identifier and server token of a declaration.
// See https://developer.apple.com/documentation/devicemanagement/manifestdeclaration
type ManifestDeclaration struct {
Identifier string
ServerToken string
}

// ManifestDeclarationItems contains a listing of manifest-type delineated declarations.
// See https://developer.apple.com/documentation/devicemanagement/declarationitemsresponse/manifestdeclarationitems
type ManifestDeclarationItems struct {
Activations []ManifestDeclaration
Expand All @@ -20,6 +22,7 @@ type ManifestDeclarationItems struct {
Management []ManifestDeclaration
}

// DeclarationItems are the set of declartions a DDM client should synchronize.
// See https://developer.apple.com/documentation/devicemanagement/declarationitemsresponse
type DeclarationItems struct {
Declarations ManifestDeclarationItems
Expand All @@ -29,6 +32,11 @@ type DeclarationItems struct {
// ManifestType returns the "type" of manifest from a declaration type.
// The result should (but is not guaranteed to) be one of "activation",
// "configuration", "asset", or "management".
//
// Generally this is the third word separated by periods in a
// declaration type. For example the manifest type of the declaration
// type "com.apple.configuration.management.test" should be
// "configuration".
func ManifestType(t string) string {
if !strings.HasPrefix(t, "com.apple.") {
return ""
Expand All @@ -41,13 +49,27 @@ func ManifestType(t string) string {
return t[0:pos]
}

// NewHash returns a newly instantiated hashing function.
type NewHash func() hash.Hash

// DIBuilder incrementally builds the DDM Declaration Items structure for later serializing.
type DIBuilder struct {
hash hash.Hash
DeclarationItems
hash.Hash
}

func NewDIBuilder(newHash func() hash.Hash) *DIBuilder {
b := &DIBuilder{
// NewDIBuilder constructs a new Declaration Items builder.
// It will panic if provided with a nil hasher.
func NewDIBuilder(newHash NewHash) *DIBuilder {
if newHash == nil {
panic("nil hasher")
}
hash := newHash()
if hash == nil {
panic("nil hash")
}
return &DIBuilder{
hash: hash,
DeclarationItems: DeclarationItems{
Declarations: ManifestDeclarationItems{
// init slices so they're non-nil for the JSON encoder.
Expand All @@ -59,20 +81,14 @@ func NewDIBuilder(newHash func() hash.Hash) *DIBuilder {
},
},
}
if newHash != nil {
b.Hash = newHash()
}
return b
}

func tokenHashWrite(h hash.Hash, d *Declaration) {
if h == nil {
return
}
h.Write([]byte(d.ServerToken))
}

func (b *DIBuilder) AddDeclarationData(d *Declaration) {
// Add adds a declaration d to the Declaration Items builder.
func (b *DIBuilder) Add(d *Declaration) {
md := ManifestDeclaration{
Identifier: d.Identifier,
ServerToken: d.ServerToken,
Expand All @@ -87,11 +103,14 @@ func (b *DIBuilder) AddDeclarationData(d *Declaration) {
case "management":
b.Declarations.Management = append(b.Declarations.Management, md)
}
tokenHashWrite(b.Hash, d)
tokenHashWrite(b.hash, d)
}

func tokenHashFinalize(h hash.Hash) string {
return fmt.Sprintf("%x", h.Sum(nil))
}

// Finalize finishes building the declarations items by computing the final Declarations Token.
func (b *DIBuilder) Finalize() {
if b.Hash != nil {
b.DeclarationItems.DeclarationsToken = fmt.Sprintf("%x", b.Hash.Sum(nil))
}
b.DeclarationItems.DeclarationsToken = tokenHashFinalize(b.hash)
}
Loading

0 comments on commit 8c6c5ab

Please sign in to comment.