Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor notification and enrollment ID capabilities #35

Merged
merged 7 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ KMFDDM=\

SUPPLEMENTAL=\
tools/*.sh \
tools/ideclr.py
tools/*.py

my: kmfddm-$(OSARCH)

Expand Down
7 changes: 7 additions & 0 deletions cmd/kmfddm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ func main() {
apihttp.GetStatusValuesHandler(storage, logger.With("handler", "get-status-values")),
"GET",
)

// notifier
mux.Handle(
"/v1/notify",
apihttp.NotifyHandler(nanoNotif, logger.With("handler", "notify")),
"POST",
)
})
}

Expand Down
7 changes: 3 additions & 4 deletions cmd/kmfddm/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/cespare/xxhash"
"github.com/jessepeterson/kmfddm/http/api"
"github.com/jessepeterson/kmfddm/http/ddm"
"github.com/jessepeterson/kmfddm/notifier"
"github.com/jessepeterson/kmfddm/storage"
"github.com/jessepeterson/kmfddm/storage/file"
"github.com/jessepeterson/kmfddm/storage/mysql"
Expand All @@ -16,15 +15,15 @@ import (
)

type allStorage interface {
notifier.EnrollmentIDFinder
api.SetAPIStorage
api.DeclarationAPIStorage
ddm.DeclarationRetriever
ddm.TokensDeclarationItemsRetriever
ddm.StatusStorage
api.EnrollmentAPIStorage
api.StatusAPIStorage
storage.Toucher
storage.EnrollmentIDRetriever
storage.DeclarationRetriever
storage.TokensDeclarationItemsRetriever
}

var hasher func() hash.Hash = func() hash.Hash { return xxhash.New() }
Expand Down
37 changes: 37 additions & 0 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,43 @@ paths:
$ref: '#/components/responses/JSONError'
parameters:
- $ref: '#/components/parameters/declarationID'
/v1/notify:
post:
description: Notify enrollment IDs by their ID or the sets they belong to, or, transitively, the declaration those sets are assigned.
security:
- basicAuth: []
responses:
'204':
description: Notification request received. See server logs for result (notification may be async).
'401':
$ref: '#/components/responses/UnauthorizedError'
'500':
$ref: '#/components/responses/JSONError'
parameters:
- in: query
name: declaration
schema:
type: array
items:
type: string
example: ['com.example.test']
explode: true
- in: query
name: set
schema:
type: array
items:
type: string
example: ['default']
explode: true
- in: query
name: id
schema:
type: array
items:
type: string
example: ['4A80F3DA-2738-434D-B95C-856811130F3B']
explode: true
components:
parameters:
declarationID:
Expand Down
31 changes: 25 additions & 6 deletions http/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"net/http"
"net/url"
"strings"

"github.com/alexedwards/flow"
"github.com/jessepeterson/kmfddm/log"
Expand Down Expand Up @@ -43,6 +44,18 @@ func jsonErrorAndLog(w http.ResponseWriter, status int, err error, msg string, l
}
}

func boolish(s string) bool {
switch strings.ToLower(s) {
case "", "0", "false", "no", "off":
return false
}
return true
}

func shouldNotify(u *url.URL) bool {
return !boolish(u.Query().Get("nonotify"))
}

func simpleJSONResourceHandler(logger log.Logger, dataFn func(context.Context, string, *url.URL) (interface{}, error)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := ctxlog.Logger(r.Context(), logger)
Expand Down Expand Up @@ -78,7 +91,7 @@ func simpleJSONResourceHandler(logger log.Logger, dataFn func(context.Context, s
}
}

func simpleChangeResourceHandler(logger log.Logger, chgFn func(context.Context, string, *url.URL) (bool, error)) http.HandlerFunc {
func simpleChangeResourceHandler(logger log.Logger, chgFn func(context.Context, string, *url.URL, bool) (bool, string, error)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := ctxlog.Logger(r.Context(), logger)
var err error
Expand All @@ -94,10 +107,18 @@ func simpleChangeResourceHandler(logger log.Logger, chgFn func(context.Context,
jsonErrorAndLog(w, http.StatusInternalServerError, err, "validating input", logger)
return
}
changed, err := chgFn(r.Context(), resource, r.URL)
notify := shouldNotify(r.URL)
changed, dataName, err := chgFn(r.Context(), resource, r.URL, notify)
chFnLogger := logger.With("msg", dataName, "changed", changed, "notify", changed && notify)
if err != nil {
jsonErrorAndLog(w, http.StatusInternalServerError, err, "retrieving data", logger)
chFnLogger.Info("err", err)
err = jsonError(w, http.StatusInternalServerError, err)
if err != nil {
logger.Info("msg", "writing response json", "err", err)
}
return
} else {
chFnLogger.Debug()
}
status := http.StatusNotModified
if changed {
Expand All @@ -113,7 +134,5 @@ func getResourceID(r *http.Request) string {
}

type Notifier interface {
DeclarationChanged(ctx context.Context, identifier string) error
EnrollmentChanged(ctx context.Context, enrollID string) error
SetChanged(ctx context.Context, setName string) error
Changed(ctx context.Context, declarations []string, sets []string, ids []string) error
}
19 changes: 12 additions & 7 deletions http/api/declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ func PutDeclarationHandler(store DeclarationAPIStorage, notifier Notifier, logge
jsonErrorAndLog(w, 0, err, "storing declaration", logger)
return
}
logger.Debug("msg", "stored declaration", "changed", changed)
notify := shouldNotify(r.URL)
logger.Debug("msg", "stored declaration", "changed", changed, "notify", changed && notify)
status := http.StatusNotModified
if changed {
status = http.StatusNoContent
}
http.Error(w, http.StatusText(status), status)
if changed {
err = notifier.DeclarationChanged(r.Context(), d.Identifier)
if changed && notify {
err = notifier.Changed(r.Context(), []string{d.Identifier}, nil, nil)
if err != nil {
logger.Info("msg", "notifying", "err", err)
return
Expand Down Expand Up @@ -169,10 +170,14 @@ func TouchDeclarationHandler(store storage.Toucher, notifier Notifier, logger lo
return
}
http.Error(w, http.StatusText(http.StatusNoContent), http.StatusNoContent)
err = notifier.DeclarationChanged(r.Context(), declarationID)
if err != nil {
logger.Info("msg", "notifying", "err", err)
return
notify := shouldNotify(r.URL)
logger.Debug("msg", "touched declaration", "notify", notify)
if notify {
err = notifier.Changed(r.Context(), []string{declarationID}, nil, nil)
if err != nil {
logger.Info("msg", "notifying", "err", err)
return
}
}
}
}
23 changes: 13 additions & 10 deletions http/api/enrollments.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ func GetEnrollmentSetsHandler(store EnrollmentAPIStorage, logger log.Logger) htt
func PutEnrollmentSetHandler(store EnrollmentAPIStorage, notifier Notifier, logger log.Logger) http.HandlerFunc {
return simpleChangeResourceHandler(
logger,
func(ctx context.Context, resource string, u *url.URL) (bool, error) {
func(ctx context.Context, resource string, u *url.URL, notify bool) (bool, string, error) {
setName := u.Query().Get("set")
if setName == "" {
return false, errors.New("empty set name")
return false, "", errors.New("empty set name")
}
changed, err := store.StoreEnrollmentSet(ctx, resource, setName)
if err == nil && changed {
err = notifier.EnrollmentChanged(ctx, resource)
if err == nil && changed && notify {
err = notifier.Changed(ctx, nil, nil, []string{resource})
if err != nil {
err = fmt.Errorf("notify enrollment: %w", err)
}
}
return changed, err
return changed, "store enrollment set", err
},
)
}
Expand All @@ -57,16 +57,19 @@ func PutEnrollmentSetHandler(store EnrollmentAPIStorage, notifier Notifier, logg
func DeleteEnrollmentSetHandler(store EnrollmentAPIStorage, notifier Notifier, logger log.Logger) http.HandlerFunc {
return simpleChangeResourceHandler(
logger,
func(ctx context.Context, resource string, u *url.URL) (bool, error) {
func(ctx context.Context, resource string, u *url.URL, notify bool) (bool, string, error) {
setName := u.Query().Get("set")
if setName == "" {
return false, errors.New("empty set name")
return false, "", errors.New("empty set name")
}
changed, err := store.RemoveEnrollmentSet(ctx, resource, setName)
if err == nil && changed {
err = notifier.EnrollmentChanged(ctx, resource)
if err == nil && changed && notify {
err = notifier.Changed(ctx, nil, nil, []string{resource})
if err != nil {
err = fmt.Errorf("notify enrollment: %w", err)
}
}
return changed, err
return changed, "remove enrollment set", err
},
)
}
23 changes: 23 additions & 0 deletions http/api/notify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package api

import (
"net/http"

"github.com/jessepeterson/kmfddm/log"
)

// NotifyHandler notifies enrollment IDs.
func NotifyHandler(notifier Notifier, logger log.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
err := notifier.Changed(
r.Context(),
r.URL.Query()["declaration"],
r.URL.Query()["set"],
r.URL.Query()["id"],
)
if err != nil {
jsonErrorAndLog(w, http.StatusInternalServerError, err, "notify changed", logger)
}
w.WriteHeader(http.StatusNoContent)
}
}
23 changes: 13 additions & 10 deletions http/api/sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ func GetSetDeclarationsHandler(store SetAPIStorage, logger log.Logger) http.Hand
func PutSetDeclarationHandler(store SetAPIStorage, notifier Notifier, logger log.Logger) http.HandlerFunc {
return simpleChangeResourceHandler(
logger,
func(ctx context.Context, resource string, u *url.URL) (bool, error) {
func(ctx context.Context, resource string, u *url.URL, notify bool) (bool, string, error) {
declarationID := u.Query().Get("declaration")
if declarationID == "" {
return false, errors.New("empty declaration")
return false, "", errors.New("empty declaration")
}
changed, err := store.StoreSetDeclaration(ctx, resource, declarationID)
if err == nil && changed {
err = notifier.SetChanged(ctx, resource)
if err == nil && changed && notify {
err = notifier.Changed(ctx, nil, []string{resource}, nil)
if err != nil {
err = fmt.Errorf("notify set: %w", err)
}
}
return changed, err
return changed, "store set declaration", err
},
)
}
Expand All @@ -60,16 +60,19 @@ func PutSetDeclarationHandler(store SetAPIStorage, notifier Notifier, logger log
func DeleteSetDeclarationHandler(store SetAPIStorage, notifier Notifier, logger log.Logger) http.HandlerFunc {
return simpleChangeResourceHandler(
logger,
func(ctx context.Context, resource string, u *url.URL) (bool, error) {
func(ctx context.Context, resource string, u *url.URL, notify bool) (bool, string, error) {
declarationID := u.Query().Get("declaration")
if declarationID == "" {
return false, errors.New("empty declaration")
return false, "", errors.New("empty declaration")
}
changed, err := store.RemoveSetDeclaration(ctx, resource, declarationID)
if err == nil && changed {
err = notifier.SetChanged(ctx, resource)
if err == nil && changed && notify {
err = notifier.Changed(ctx, nil, []string{resource}, nil)
if err != nil {
err = fmt.Errorf("notify set: %w", err)
}
}
return changed, err
return changed, "remove set declaration", err
},
)
}
Expand Down
14 changes: 3 additions & 11 deletions http/ddm/ddm.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/jessepeterson/kmfddm/ddm"
"github.com/jessepeterson/kmfddm/log"
"github.com/jessepeterson/kmfddm/log/ctxlog"
"github.com/jessepeterson/kmfddm/storage"
)

const (
Expand All @@ -30,10 +31,6 @@ func parseDeclPath(r *http.Request) (string, string, error) {
return split[0], split[1], nil
}

type DeclarationRetriever interface {
RetrieveEnrollmentDeclarationJSON(ctx context.Context, declarationID, declarationType, enrollmentID string) ([]byte, error)
}

func ErrorAndLog(w http.ResponseWriter, status int, logger log.Logger, msg string, err error) {
logger.Info("msg", msg, "err", err)
http.Error(w, http.StatusText(status), status)
Expand All @@ -42,7 +39,7 @@ func ErrorAndLog(w http.ResponseWriter, status int, logger log.Logger, msg strin
// DeclarationHandler creates a handler that fetches and returns a single declaration.
// The request URL path is assumed to contain the declaration type and identifier.
// This probably requires the handler to have the path prefix stripped before use.
func DeclarationHandler(store DeclarationRetriever, logger log.Logger) http.HandlerFunc {
func DeclarationHandler(store storage.DeclarationRetriever, logger log.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := ctxlog.Logger(r.Context(), logger)
declarationType, declarationID, err := parseDeclPath(r)
Expand Down Expand Up @@ -74,14 +71,9 @@ func DeclarationHandler(store DeclarationRetriever, logger log.Logger) http.Hand
}
}

type TokensDeclarationItemsRetriever interface {
RetrieveDeclarationItemsJSON(ctx context.Context, enrollmentID string) ([]byte, error)
RetrieveTokensJSON(ctx context.Context, enrollmentID string) ([]byte, error)
}

// TokensDeclarationItemsHandler creates a handler that fetchs and returns either
// the tokens or declaration items JSON for an erollment ID depending on tokens.
func TokensDeclarationItemsHandler(store TokensDeclarationItemsRetriever, tokens bool, logger log.Logger) http.HandlerFunc {
func TokensDeclarationItemsHandler(store storage.TokensDeclarationItemsRetriever, tokens bool, logger log.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := ctxlog.Logger(r.Context(), logger)
var err error
Expand Down
Loading