Skip to content
This repository has been archived by the owner on Jun 10, 2018. It is now read-only.

Commit

Permalink
Complete listing of MDM Commands as structs (#6)
Browse files Browse the repository at this point in the history
* Add struct for CertificateList response.

* Add structs for all possible MDM command request types.
Add definitions for each setting which may be changed by the Settings command.
Add some error enums.

* Move response fixtures to their own file.
Add very basic tests for commands.
Add prefix to each error type to stop name collision
Add more response types.
Fix response tests to use new fixture location.

* Further simple tests for MDM commands.

* Add plist responses based on real world responses to use as test fixtures.
Support InstalledApplicationList command.
Add struct for Error response.

* Add InstalledApplicationList response item struct.

* Remove duplicate definition of InstalledApplicationListItem

* Add simple test for error chain.
Add ErrorChain to response struct.

* Add example response for InstalledApplicationList

* Add test for InstalledApplicationListResponse

* int field did not have enough storage for some installed apps, used uint32.
  • Loading branch information
mosen authored and groob committed Oct 5, 2016
1 parent 343748b commit 1b3e0e0
Show file tree
Hide file tree
Showing 13 changed files with 1,850 additions and 1,044 deletions.
175 changes: 160 additions & 15 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type CommandRequest struct {
AccountConfiguration
ScheduleOSUpdateScan
InstallProfile
InstalledApplicationList
}

// Payload is an MDM payload
Expand All @@ -30,30 +31,154 @@ type command struct {
DeviceInformation
InstallApplication
InstallProfile
InstalledApplicationList
AccountConfiguration
ScheduleOSUpdateScan
}

// InstallApplication is an InstallApplication MDM Command
type InstallApplication struct {
ITunesStoreID int `plist:"iTunesStoreID,omitempty" json:"itunes_store_id,omitempty"`
Identifier string `plist:",omitempty" json:"identifier,omitempty"`
ManifestURL string `plist:",omitempty" json:"manifest_url,omitempty"`
ManagementFlags int `plist:",omitempty" json:"management_flags,omitempty"`
NotManaged bool `plist:",omitempty" json:"not_managed,omitempty"`
// TODO: add remaining optional fields
}
// The following commands are in the order provided by the apple documentation.

// InstallProfile is an InstallProfile MDM Command
type InstallProfile struct {
Payload []byte `plist:",omitempty" json:"payload,omitempty"`
}

type RemoveProfile struct {
Identifier string `plist:",omitempty" json:"identifier,omitempty"`
}

type InstallProvisioningProfile struct {
ProvisioningProfile []byte `plist:",omitempty" json:"provisioning_profile,omitempty"`
}

type RemoveProvisioningProfile struct {
UUID string `plist:",omitempty" json:"uuid,omitempty"`
}

type InstalledApplicationList struct {
Identifiers []string `plist:",omitempty" json:"identifiers,omitempty"`
ManagedAppsOnly bool `plist:",omitempty" json:"managed_apps_only,omitempty"`
}

// DeviceInformation is a DeviceInformation MDM Command
type DeviceInformation struct {
Queries []string `plist:",omitempty" json:"queries,omitempty"`
}

type DeviceLock struct {
PIN string `json:"pin,omitempty"`
Message string `plist:",omitempty" json:"message,omitempty"`
PhoneNumber string `plist:",omitempty" json:"phone_number,omitempty"`
}

type ClearPasscode struct {
UnlockToken []byte `plist:",omitempty" json:"unlock_token,omitempty"`
}

type EraseDevice struct {
PIN string `plist:",omitempty" json:"pin,omitempty"`
}

type RequestMirroring struct {
DestinationName string `plist:",omitempty" json:"destination_name,omitempty"`
DestinationDeviceID string `plist:",omitempty" json:"destination_device_id,omitempty"`
ScanTime string `plist:",omitempty" json:"scan_time,omitempty"`
Password string `plist:",omitempty" json:"password,omitempty"`
}

type Restrictions struct {
ProfileRestrictions bool `plist:",omitempty" json:"restrictions,omitempty"`
}

type DeleteUser struct {
UserName string `plist:",omitempty" json:"user_name,omitempty"`
ForceDeletion bool `plist:",omitempty" json:"force_deletion,omitempty"`
}

type EnableLostMode struct {
Message string `plist:",omitempty" json:"message,omitempty"`
PhoneNumber string `plist:",omitempty" json:"phone_number,omitempty"`
Footnote string `plist:",omitempty" json:"footnote,omitempty"`
}

// InstallApplication is an InstallApplication MDM Command
type InstallApplication struct {
ITunesStoreID int `plist:"iTunesStoreID,omitempty" json:"itunes_store_id,omitempty"`
Identifier string `plist:",omitempty" json:"identifier,omitempty"`
ManifestURL string `plist:",omitempty" json:"manifest_url,omitempty"`
ManagementFlags int `plist:",omitempty" json:"management_flags,omitempty"`
NotManaged bool `plist:",omitempty" json:"not_managed,omitempty"`
ChangeManagementState string `plist:",omitempty" json:"change_management_state,omitempty"`
Options InstallApplicationOptions `plist:",omitempty" json:"options,omitempty"`
// TODO: add remaining optional fields
}

type InstallApplicationConfiguration struct {
// TODO: managed app config
}

type InstallApplicationOptions struct {
NotManaged bool `plist:",omitempty" json:"not_managed,omitempty"`
PurchaseMethod int `plist:",omitempty" json:"purchase_method,omitempty"`
}

type ApplyRedemptionCode struct {
Identifier string `plist:",omitempty" json:"identifier,omitempty"`
RedemptionCode string `plist:",omitempty" json:"redemption_code,omitempty"`
}

type ManagedApplicationList struct {
Identifiers []string `plist:",omitempty" json:"identifiers,omitempty"`
}

type RemoveApplication struct {
Identifier string `json:"identifier,omitempty"`
}

type InviteToProgram struct {
ProgramID string `json:"program_id,omitempty"`
InvitationURL string `json:"invitation_url,omitempty"`
}

type ValidateApplications struct {
Identifiers []string `plist:",omitempty" json:"identifiers,omitempty"`
}

type InstallMedia struct {
ITunesStoreID int `plist:"iTunesStoreID,omitempty" json:"itunes_store_id,omitempty"`
MediaURL string `plist:",omitempty" json:"media_url,omitempty"`
MediaType string `json:"media_type"`
// TODO: media url fields
}

type RemoveMedia struct {
MediaType string `json:"media_type"`
ITunesStoreID int `plist:"iTunesStoreID,omitempty" json:"itunes_store_id,omitempty"`
PersistentID string `plist:",omitempty" json:"persistent_id,omitempty"`
}

type Settings struct {
Settings []Setting `json:"settings"`
}

type ManagedApplicationConfiguration struct {
Identifiers []string `plist:",omitempty" json:"identifiers,omitempty"`
}

type ApplicationConfiguration struct {
Identifier string `json:"identifier,omitempty"`
Configuration map[string]string `plist:",omitempty" json:"configuration,omitempty"` // TODO: string map is temporary
}

type ManagedApplicationAttributes struct {
Identifiers []string `plist:",omitempty" json:"identifiers,omitempty"`
}

type ManagedApplicationFeedback struct {
Identifiers []string `plist:",omitempty" json:"identifiers,omitempty"`
DeleteFeedback bool `plist:",omitempty" json:"delete_feedback,omitempty"`
}

// AccountConfiguration is an MDM command to create a primary user on OS X
// It allows skipping the UI to set up a user.
type AccountConfiguration struct {
Expand All @@ -62,11 +187,6 @@ type AccountConfiguration struct {
AutoSetupAdminAccounts []AdminAccount `plist:",omitempty" json:"auto_setup_admin_accounts,omitempty"`
}

// ScheduleOSUpdateScan schedules an OS SoftwareUpdate check
type ScheduleOSUpdateScan struct {
Force bool `plist:",omitempty" json:"force,omitempty"`
}

// AdminAccount is the configuration for the
// Admin account created during Setup Assistant
type AdminAccount struct {
Expand All @@ -76,6 +196,21 @@ type AdminAccount struct {
Hidden bool `plist:"hidden,omitempty" json:"hidden,omitempty"`
}

type OSUpdate struct {
ProductKey string `json:"product_key"`
InstallAction string `json:"install_action"`
}

// ScheduleOSUpdate runs update(s) immediately
type ScheduleOSUpdate struct {
Updates []OSUpdate `plist:",omitempty" json:"updates,omitempty"`
}

// ScheduleOSUpdateScan schedules a (background) OS SoftwareUpdate check
type ScheduleOSUpdateScan struct {
Force bool `plist:",omitempty" json:"force,omitempty"`
}

type data []byte

func newPayload(requestType string) *Payload {
Expand All @@ -94,8 +229,16 @@ func NewPayload(request *CommandRequest) (*Payload, error) {
case "ScheduleOSUpdateScan":
payload.Command.ScheduleOSUpdateScan = request.ScheduleOSUpdateScan
case "ProfileList",
"SecurityInfo",
"ProvisioningProfileList",
"CertificateList",
"SecurityInfo",
"StopMirroring",
"ClearRestrictionsPassword",
"UsersList",
"LogOutUser",
"DisableLostMode",
"DeviceLocation",
"ManagedMediaList",
"OSUpdateStatus",
"DeviceConfigured",
"AvailableOSUpdates":
Expand All @@ -106,6 +249,8 @@ func NewPayload(request *CommandRequest) (*Payload, error) {
payload.Command.InstallProfile = request.InstallProfile
case "AccountConfiguration":
payload.Command.AccountConfiguration = request.AccountConfiguration
case "InstalledApplicationList":
payload.Command.InstalledApplicationList = request.InstalledApplicationList
default:
return nil, fmt.Errorf("Unsupported MDM RequestType %v", requestType)
}
Expand Down
116 changes: 116 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package mdm

import (
"encoding/json"
"fmt"
"github.com/groob/plist"
"testing"
)

// Basic tests will attempt to marshal and unmarshal mdm command structures to identify any naming or tag errors.

// Make sure a command can be marshalled to json
func testMarshalJSON(t *testing.T, cmd interface{}) {
jsonCmd, err := json.Marshal(cmd)
if err != nil {
t.Error(err)
}
fmt.Println(string(jsonCmd))
}

// Make sure a command can be marshalled to plist
func testMarshalPlist(t *testing.T, cmd interface{}) {
plistCmd, err := plist.MarshalIndent(cmd, "\t")
if err != nil {
t.Error(err)
}
fmt.Println(string(plistCmd))
}

func TestInstallProfile(t *testing.T) {
cmd := InstallProfile{Payload: []byte{00}}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestRemoveProfile(t *testing.T) {
cmd := RemoveProfile{Identifier: "io.micromdm.test.profile"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestInstallProvisioningProfile(t *testing.T) {
cmd := InstallProvisioningProfile{ProvisioningProfile: []byte{00}}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestRemoveProvisioningProfile(t *testing.T) {
cmd := RemoveProvisioningProfile{UUID: "1111-2222-3333"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestInstalledApplicationList(t *testing.T) {
cmd := InstalledApplicationList{Identifiers: []string{"io.micromdm.application"}, ManagedAppsOnly: true}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestDeviceInformation(t *testing.T) {
cmd := DeviceInformation{Queries: []string{"SerialNumber"}}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestDeviceLock(t *testing.T) {
cmd := DeviceLock{PIN: "123456", Message: "Locked", PhoneNumber: "123-4567"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestClearPasscode(t *testing.T) {
cmd := ClearPasscode{UnlockToken: []byte{00}}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestEraseDevice(t *testing.T) {
cmd := EraseDevice{PIN: "123456"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestRequestMirroring(t *testing.T) {
cmd := RequestMirroring{DestinationName: "Apple TV", ScanTime: "30", Password: "sekret"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

//func TestRestrictions(t *testing.T) {
// cmd := Restrictions{}
//}

func TestDeleteUser(t *testing.T) {
cmd := DeleteUser{UserName: "joe", ForceDeletion: false}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestEnableLostMode(t *testing.T) {
cmd := EnableLostMode{Message: "Lost!", PhoneNumber: "123-4567", Footnote: "This is lost"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestInstallApplication(t *testing.T) {
cmd := InstallApplication{ITunesStoreID: 1234567}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}

func TestApplyRedemptionCode(t *testing.T) {
cmd := ApplyRedemptionCode{Identifier: "id", RedemptionCode: "abcdefg"}
testMarshalJSON(t, cmd)
testMarshalPlist(t, cmd)
}
Loading

0 comments on commit 1b3e0e0

Please sign in to comment.