From ac46c3c56b04bae5c98104a9e9f55875b3eaa918 Mon Sep 17 00:00:00 2001 From: Victor Vrantchan Date: Sat, 18 Mar 2017 04:52:04 +0000 Subject: [PATCH] add depsync package --- depsync/depsync.go | 84 ++++++++ depsync/event.go | 83 ++++++++ depsync/internal/depsyncproto/depsync.go | 3 + depsync/internal/depsyncproto/depsync.pb.go | 208 ++++++++++++++++++++ depsync/internal/depsyncproto/depsync.proto | 26 +++ device/checkin.go | 1 - device/db.go | 131 +++++++++--- lock.json | 4 +- manifest.json | 3 + serve.go | 65 ++++++ 10 files changed, 580 insertions(+), 28 deletions(-) create mode 100644 depsync/depsync.go create mode 100644 depsync/event.go create mode 100644 depsync/internal/depsyncproto/depsync.go create mode 100644 depsync/internal/depsyncproto/depsync.pb.go create mode 100644 depsync/internal/depsyncproto/depsync.proto delete mode 100644 device/checkin.go diff --git a/depsync/depsync.go b/depsync/depsync.go new file mode 100644 index 00000000..c9ba076d --- /dev/null +++ b/depsync/depsync.go @@ -0,0 +1,84 @@ +package depsync + +import ( + "fmt" + "log" + "time" + + "github.com/micromdm/dep" + "github.com/micromdm/nano/pubsub" +) + +const ( + SyncTopic = "mdm.DepSync" +) + +type Syncer interface { + privateDEPSyncer() bool +} + +type watcher struct { + initial bool + config *dep.Config + client dep.Client + publisher pubsub.Publisher +} + +type cursor struct { + Value string + CreatedAt time.Time +} + +// A cursor is valid for a week. +func (c cursor) Valid() bool { + expiration := time.Now().Add(24 * 7 * time.Hour) + if c.CreatedAt.After(expiration) { + return false + } + return true +} + +func New(client dep.Client, pub pubsub.Publisher) (Syncer, error) { + sync := &watcher{ + publisher: pub, + client: client, + } + + go func() { + if err := sync.Run(); err != nil { + log.Println("DEP watcher failed: ", err) + } + }() + return sync, nil +} + +// TODO this is private temporarily until the interface can be defined +func (w *watcher) privateDEPSyncer() bool { + return true +} + +func (w *watcher) Run() error { + ticker := time.NewTicker(10 * time.Second).C + cursor := "" + for { + resp, err := w.client.FetchDevices(dep.Limit(100), dep.Cursor(cursor)) + if err != nil { + return err + } + fmt.Printf("more=%v, cursor=%s, fetched=%v\n", resp.MoreToFollow, resp.Cursor, resp.FetchedUntil) + cursor = resp.Cursor + e := NewEvent(resp.Devices) + data, err := MarshalEvent(e) + if err != nil { + return err + } + if err := w.publisher.Publish(SyncTopic, data); err != nil { + return err + } + if !resp.MoreToFollow { + break + } + <-ticker + } + return nil +} diff --git a/depsync/event.go b/depsync/event.go new file mode 100644 index 00000000..b1648298 --- /dev/null +++ b/depsync/event.go @@ -0,0 +1,83 @@ +package depsync + +import ( + "time" + + "github.com/gogo/protobuf/proto" + "github.com/micromdm/dep" + uuid "github.com/satori/go.uuid" + + "github.com/micromdm/nano/depsync/internal/depsyncproto" +) + +type Event struct { + ID string + Time time.Time + Devices []dep.Device +} + +func NewEvent(devices []dep.Device) *Event { + event := Event{ + ID: uuid.NewV4().String(), + Time: time.Now().UTC(), + Devices: devices, + } + return &event +} + +// MarshalEvent serializes an event to a protocol buffer wire format. +func MarshalEvent(e *Event) ([]byte, error) { + var devices []*depsyncproto.Device + for _, d := range e.Devices { + devices = append(devices, &depsyncproto.Device{ + SerialNumber: d.SerialNumber, + Model: d.Model, + Description: d.Description, + Color: d.Color, + AssetTag: d.AssetTag, + ProfileUuid: d.ProfileUUID, + ProfileAssignTime: d.ProfileAssignTime.UnixNano(), + ProfilePushTime: d.ProfilePushTime.UnixNano(), + DeviceAssignedDate: d.DeviceAssignedDate.UnixNano(), + DeviceAssignedBy: d.DeviceAssignedBy, + OpType: d.OpType, + OpDate: d.OpDate.UnixNano(), + }) + } + return proto.Marshal(&depsyncproto.Event{ + Id: e.ID, + Time: e.Time.UnixNano(), + Devices: devices, + }) +} + +// UnmarshalEvent parses a protocol buffer representation of data into +// the Event. +func UnmarshalEvent(data []byte, e *Event) error { + var pb depsyncproto.Event + if err := proto.Unmarshal(data, &pb); err != nil { + return err + } + e.ID = pb.GetId() + e.Time = time.Unix(0, pb.GetTime()).UTC() + protodev := pb.GetDevices() + var devices []dep.Device + for _, d := range protodev { + devices = append(devices, dep.Device{ + SerialNumber: d.GetSerialNumber(), + Model: d.GetModel(), + Description: d.GetDescription(), + Color: d.GetColor(), + AssetTag: d.GetAssetTag(), + ProfileUUID: d.GetProfileUuid(), + ProfileAssignTime: time.Unix(0, d.GetProfileAssignTime()).UTC(), + ProfilePushTime: time.Unix(0, d.GetProfilePushTime()).UTC(), + DeviceAssignedDate: time.Unix(0, d.GetDeviceAssignedDate()).UTC(), + DeviceAssignedBy: d.GetDeviceAssignedBy(), + OpType: d.GetOpType(), + OpDate: time.Unix(0, d.GetOpDate()).UTC(), + }) + } + e.Devices = devices + return nil +} diff --git a/depsync/internal/depsyncproto/depsync.go b/depsync/internal/depsyncproto/depsync.go new file mode 100644 index 00000000..e5cb3e86 --- /dev/null +++ b/depsync/internal/depsyncproto/depsync.go @@ -0,0 +1,3 @@ +package depsyncproto + +//go:generate protoc --go_out=. depsync.proto diff --git a/depsync/internal/depsyncproto/depsync.pb.go b/depsync/internal/depsyncproto/depsync.pb.go new file mode 100644 index 00000000..c0eb87ff --- /dev/null +++ b/depsync/internal/depsyncproto/depsync.pb.go @@ -0,0 +1,208 @@ +// Code generated by protoc-gen-go. +// source: depsync.proto +// DO NOT EDIT! + +/* +Package depsyncproto is a generated protocol buffer package. + +It is generated from these files: + depsync.proto + +It has these top-level messages: + Event + Device +*/ +package depsyncproto + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Event struct { + Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Time int64 `protobuf:"varint,2,opt,name=time" json:"time,omitempty"` + Devices []*Device `protobuf:"bytes,3,rep,name=devices" json:"devices,omitempty"` +} + +func (m *Event) Reset() { *m = Event{} } +func (m *Event) String() string { return proto.CompactTextString(m) } +func (*Event) ProtoMessage() {} +func (*Event) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Event) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Event) GetTime() int64 { + if m != nil { + return m.Time + } + return 0 +} + +func (m *Event) GetDevices() []*Device { + if m != nil { + return m.Devices + } + return nil +} + +type Device struct { + SerialNumber string `protobuf:"bytes,1,opt,name=serial_number,json=serialNumber" json:"serial_number,omitempty"` + Model string `protobuf:"bytes,2,opt,name=model" json:"model,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` + Color string `protobuf:"bytes,4,opt,name=color" json:"color,omitempty"` + AssetTag string `protobuf:"bytes,5,opt,name=asset_tag,json=assetTag" json:"asset_tag,omitempty"` + ProfileStatus string `protobuf:"bytes,6,opt,name=profile_status,json=profileStatus" json:"profile_status,omitempty"` + ProfileUuid string `protobuf:"bytes,7,opt,name=profile_uuid,json=profileUuid" json:"profile_uuid,omitempty"` + ProfileAssignTime int64 `protobuf:"varint,8,opt,name=profile_assign_time,json=profileAssignTime" json:"profile_assign_time,omitempty"` + ProfilePushTime int64 `protobuf:"varint,9,opt,name=profile_push_time,json=profilePushTime" json:"profile_push_time,omitempty"` + DeviceAssignedDate int64 `protobuf:"varint,10,opt,name=device_assigned_date,json=deviceAssignedDate" json:"device_assigned_date,omitempty"` + DeviceAssignedBy string `protobuf:"bytes,11,opt,name=device_assigned_by,json=deviceAssignedBy" json:"device_assigned_by,omitempty"` + OpType string `protobuf:"bytes,12,opt,name=op_type,json=opType" json:"op_type,omitempty"` + OpDate int64 `protobuf:"varint,13,opt,name=op_date,json=opDate" json:"op_date,omitempty"` +} + +func (m *Device) Reset() { *m = Device{} } +func (m *Device) String() string { return proto.CompactTextString(m) } +func (*Device) ProtoMessage() {} +func (*Device) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Device) GetSerialNumber() string { + if m != nil { + return m.SerialNumber + } + return "" +} + +func (m *Device) GetModel() string { + if m != nil { + return m.Model + } + return "" +} + +func (m *Device) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Device) GetColor() string { + if m != nil { + return m.Color + } + return "" +} + +func (m *Device) GetAssetTag() string { + if m != nil { + return m.AssetTag + } + return "" +} + +func (m *Device) GetProfileStatus() string { + if m != nil { + return m.ProfileStatus + } + return "" +} + +func (m *Device) GetProfileUuid() string { + if m != nil { + return m.ProfileUuid + } + return "" +} + +func (m *Device) GetProfileAssignTime() int64 { + if m != nil { + return m.ProfileAssignTime + } + return 0 +} + +func (m *Device) GetProfilePushTime() int64 { + if m != nil { + return m.ProfilePushTime + } + return 0 +} + +func (m *Device) GetDeviceAssignedDate() int64 { + if m != nil { + return m.DeviceAssignedDate + } + return 0 +} + +func (m *Device) GetDeviceAssignedBy() string { + if m != nil { + return m.DeviceAssignedBy + } + return "" +} + +func (m *Device) GetOpType() string { + if m != nil { + return m.OpType + } + return "" +} + +func (m *Device) GetOpDate() int64 { + if m != nil { + return m.OpDate + } + return 0 +} + +func init() { + proto.RegisterType((*Event)(nil), "depsyncproto.Event") + proto.RegisterType((*Device)(nil), "depsyncproto.Device") +} + +func init() { proto.RegisterFile("depsync.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 361 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x91, 0x51, 0x8b, 0xd3, 0x40, + 0x10, 0xc7, 0x69, 0x73, 0x4d, 0x2f, 0xd3, 0xe4, 0xd4, 0xb1, 0xe0, 0x82, 0x2f, 0xf1, 0x44, 0x28, + 0x22, 0x41, 0xf4, 0x13, 0x9c, 0x9c, 0xaf, 0x22, 0xb1, 0x3e, 0xf9, 0x10, 0xb6, 0xd9, 0xb1, 0xb7, + 0x90, 0x66, 0x97, 0xec, 0xa6, 0x90, 0x6f, 0xe9, 0x47, 0x92, 0xce, 0x6e, 0xa0, 0xfa, 0x96, 0xf9, + 0xff, 0x7e, 0x33, 0x13, 0x66, 0xa1, 0x50, 0x64, 0xdd, 0xd4, 0xb7, 0x95, 0x1d, 0x8c, 0x37, 0x98, + 0xc7, 0x92, 0xab, 0xfb, 0x5f, 0xb0, 0xfa, 0x7a, 0xa6, 0xde, 0xe3, 0x1d, 0x2c, 0xb5, 0x12, 0x8b, + 0x72, 0xb1, 0xcb, 0xea, 0xa5, 0x56, 0x88, 0x70, 0xe3, 0xf5, 0x89, 0xc4, 0xb2, 0x5c, 0xec, 0x92, + 0x9a, 0xbf, 0xb1, 0x82, 0xb5, 0xa2, 0xb3, 0x6e, 0xc9, 0x89, 0xa4, 0x4c, 0x76, 0x9b, 0x4f, 0xdb, + 0xea, 0x7a, 0x58, 0xf5, 0xc8, 0xb0, 0x9e, 0xa5, 0xfb, 0x3f, 0x09, 0xa4, 0x21, 0xc3, 0xb7, 0x50, + 0x38, 0x1a, 0xb4, 0xec, 0x9a, 0x7e, 0x3c, 0x1d, 0x68, 0x88, 0x9b, 0xf2, 0x10, 0x7e, 0xe3, 0x0c, + 0xb7, 0xb0, 0x3a, 0x19, 0x45, 0x1d, 0x2f, 0xcd, 0xea, 0x50, 0x60, 0x09, 0x1b, 0x45, 0xae, 0x1d, + 0xb4, 0xf5, 0xda, 0xf4, 0x22, 0x61, 0x76, 0x1d, 0x5d, 0xfa, 0x5a, 0xd3, 0x99, 0x41, 0xdc, 0x84, + 0x3e, 0x2e, 0xf0, 0x35, 0x64, 0xd2, 0x39, 0xf2, 0x8d, 0x97, 0x47, 0xb1, 0x62, 0x72, 0xcb, 0xc1, + 0x5e, 0x1e, 0xf1, 0x1d, 0xdc, 0xd9, 0xc1, 0xfc, 0xd6, 0x1d, 0x35, 0xce, 0x4b, 0x3f, 0x3a, 0x91, + 0xb2, 0x51, 0xc4, 0xf4, 0x07, 0x87, 0xf8, 0x06, 0xf2, 0x59, 0x1b, 0x47, 0xad, 0xc4, 0x3a, 0x2c, + 0x8f, 0xd9, 0xcf, 0x51, 0x2b, 0xac, 0xe0, 0xe5, 0xac, 0x48, 0xe7, 0xf4, 0xb1, 0x6f, 0xf8, 0x6e, + 0xb7, 0x7c, 0xb7, 0x17, 0x11, 0x3d, 0x30, 0xd9, 0x5f, 0x8e, 0xf8, 0x1e, 0xe6, 0xb0, 0xb1, 0xa3, + 0x7b, 0x0a, 0x76, 0xc6, 0xf6, 0xb3, 0x08, 0xbe, 0x8f, 0xee, 0x89, 0xdd, 0x8f, 0xb0, 0x0d, 0xb7, + 0x8c, 0xa3, 0x49, 0x35, 0x4a, 0x7a, 0x12, 0xc0, 0x3a, 0x06, 0xf6, 0x10, 0xd1, 0xa3, 0xf4, 0x84, + 0x1f, 0x00, 0xff, 0xef, 0x38, 0x4c, 0x62, 0xc3, 0xbf, 0xfd, 0xfc, 0x5f, 0xff, 0xcb, 0x84, 0xaf, + 0x60, 0x6d, 0x6c, 0xe3, 0x27, 0x4b, 0x22, 0x67, 0x25, 0x35, 0x76, 0x3f, 0x59, 0x8a, 0x80, 0x77, + 0x15, 0xbc, 0x2b, 0x35, 0xf6, 0x32, 0xff, 0x90, 0xf2, 0x4b, 0x7f, 0xfe, 0x1b, 0x00, 0x00, 0xff, + 0xff, 0x1d, 0x9a, 0x90, 0xb5, 0x55, 0x02, 0x00, 0x00, +} diff --git a/depsync/internal/depsyncproto/depsync.proto b/depsync/internal/depsyncproto/depsync.proto new file mode 100644 index 00000000..dcb02bcf --- /dev/null +++ b/depsync/internal/depsyncproto/depsync.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package depsyncproto; + +message Event { + string id = 1; + int64 time = 2; + repeated Device devices = 3; +} + +message Device { + string serial_number = 1; + string model = 2; + string description = 3; + string color = 4; + string asset_tag = 5; + string profile_status = 6; + string profile_uuid = 7; + int64 profile_assign_time = 8; + int64 profile_push_time = 9; + int64 device_assigned_date = 10; + string device_assigned_by = 11; + + string op_type = 12; + int64 op_date = 13; +} diff --git a/device/checkin.go b/device/checkin.go deleted file mode 100644 index 76a9bfa3..00000000 --- a/device/checkin.go +++ /dev/null @@ -1 +0,0 @@ -package device diff --git a/device/db.go b/device/db.go index c3df785e..fbb48ef1 100644 --- a/device/db.go +++ b/device/db.go @@ -5,6 +5,7 @@ import ( "github.com/boltdb/bolt" "github.com/micromdm/nano/checkin" + "github.com/micromdm/nano/depsync" "github.com/micromdm/nano/pubsub" "github.com/pkg/errors" uuid "github.com/satori/go.uuid" @@ -46,16 +47,22 @@ func (db *DB) Save(dev *Device) error { if err != nil { return errors.Wrap(err, "marshalling device") } - indexes := []string{dev.UDID, dev.UUID} + // store an array of indices to reference the UUID, which will be the + // key used to store the actual device. + indexes := []string{dev.UDID, dev.SerialNumber} for _, idx := range indexes { if idx == "" { continue } key := []byte(idx) - if err := bkt.Put(key, devproto); err != nil { + if err := bkt.Put(key, []byte(dev.UUID)); err != nil { return errors.Wrap(err, "put device to boltdb") } } + key := []byte(dev.UUID) + if err := bkt.Put(key, devproto); err != nil { + return errors.Wrap(err, "put device to boltdb") + } return tx.Commit() } @@ -72,10 +79,34 @@ func (db *DB) DeviceByUDID(udid string) (*Device, error) { var dev Device err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(DeviceBucket)) - v := b.Get([]byte(udid)) - if v == nil { + idx := b.Get([]byte(udid)) + if idx == nil { return ¬Found{"Device", fmt.Sprintf("udid %s", udid)} } + v := b.Get(idx) + if idx == nil { + return ¬Found{"Device", fmt.Sprintf("uuid %s", string(idx))} + } + return UnmarshalDevice(v, &dev) + }) + if err != nil { + return nil, err + } + return &dev, nil +} + +func (db *DB) DeviceBySerial(serial string) (*Device, error) { + var dev Device + err := db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(DeviceBucket)) + idx := b.Get([]byte(serial)) + if idx == nil { + return ¬Found{"Device", fmt.Sprintf("serial %s", serial)} + } + v := b.Get(idx) + if idx == nil { + return ¬Found{"Device", fmt.Sprintf("uuid %s", string(idx))} + } return UnmarshalDevice(v, &dev) }) if err != nil { @@ -107,6 +138,11 @@ func (db *DB) pollCheckin(sub pubsub.Subscriber) error { return errors.Wrapf(err, "subscribing devices to %s topic", checkin.CheckoutTopic) } + depSyncEvents, err := sub.Subscribe("devices", depsync.SyncTopic) + if err != nil { + return errors.Wrapf(err, + "subscribing devices to %s topic", depsync.SyncTopic) + } go func() { for { select { @@ -116,28 +152,36 @@ func (db *DB) pollCheckin(sub pubsub.Subscriber) error { fmt.Println(err) continue } + newDevice := new(Device) + bySerial, err := db.DeviceBySerial(ev.Command.SerialNumber) + if err == nil && bySerial != nil { // must be a DEP device + newDevice = bySerial + } + if err != nil && !isNotFound(err) { + fmt.Println(err) // some other issue is going on + } _, err = db.DeviceByUDID(ev.Command.UDID) - if err != nil { - if isNotFound(err) { - if err := db.Save(&Device{ - UUID: uuid.NewV4().String(), - UDID: ev.Command.UDID, - OSVersion: ev.Command.OSVersion, - BuildVersion: ev.Command.BuildVersion, - ProductName: ev.Command.ProductName, - SerialNumber: ev.Command.SerialNumber, - IMEI: ev.Command.IMEI, - MEID: ev.Command.MEID, - DeviceName: ev.Command.DeviceName, - // Challenge: ev.Command.Challenge, - Model: ev.Command.Model, - ModelName: ev.Command.ModelName, - }); err != nil { - fmt.Println(err) - continue - } - continue - } + if err != nil && isNotFound(err) { // never checked in + fmt.Printf("checking in new device %s\n", ev.Command.SerialNumber) + } else if err != nil { + fmt.Println(err) + } else if err == nil { + fmt.Printf("re-enrolling device %s\n", ev.Command.SerialNumber) + } + newDevice.UUID = uuid.NewV4().String() + newDevice.UDID = ev.Command.UDID + newDevice.OSVersion = ev.Command.OSVersion + newDevice.BuildVersion = ev.Command.BuildVersion + newDevice.ProductName = ev.Command.ProductName + newDevice.SerialNumber = ev.Command.SerialNumber + newDevice.IMEI = ev.Command.IMEI + newDevice.MEID = ev.Command.MEID + newDevice.DeviceName = ev.Command.DeviceName + newDevice.Model = ev.Command.Model + newDevice.ModelName = ev.Command.ModelName + // Challenge: ev.Command.Challenge, // FIXME: @groob why is this commented out? + + if err := db.Save(newDevice); err != nil { fmt.Println(err) continue } @@ -164,6 +208,43 @@ func (db *DB) pollCheckin(sub pubsub.Subscriber) error { fmt.Println(err) continue } + case event := <-depSyncEvents: + var ev depsync.Event + if err := depsync.UnmarshalEvent(event.Message, &ev); err != nil { + fmt.Println(err) + continue + } + fmt.Printf("got %d devices from DEP\n", len(ev.Devices)) + for _, d := range ev.Devices { + newDevice := new(Device) + bySerial, err := db.DeviceBySerial(d.SerialNumber) + if err == nil && bySerial != nil { // must be a DEP device + fmt.Printf("existing device checked in from DEP: %s\n", d.SerialNumber) + newDevice = bySerial + } + if err != nil && !isNotFound(err) { + fmt.Println(err) // some other issue is going on + continue + } + if newDevice.UUID == "" { // previously unknown + newDevice.UUID = uuid.NewV4().String() + } + newDevice.SerialNumber = d.SerialNumber + newDevice.Model = d.Model + newDevice.Description = d.Description + newDevice.Color = d.Color + newDevice.AssetTag = d.AssetTag + newDevice.DEPProfileStatus = DEPProfileStatus(d.ProfileStatus) + newDevice.DEPProfileUUID = d.ProfileUUID + newDevice.DEPProfileAssignTime = d.ProfileAssignTime + newDevice.DEPProfileAssignedDate = d.DeviceAssignedDate + newDevice.DEPProfileAssignedBy = d.DeviceAssignedBy + // TODO: deal with sync fields OpType, OpDate + if err := db.Save(newDevice); err != nil { + fmt.Println(err) + continue + } + } case event := <-checkoutEvents: var ev checkin.Event if err := checkin.UnmarshalEvent(event.Message, &ev); err != nil { diff --git a/lock.json b/lock.json index 643d4fd6..6f2353ba 100644 --- a/lock.json +++ b/lock.json @@ -1,5 +1,5 @@ { - "memo": "8083a2cf13559fb206e86028e580bb739c2704e8e052742970dd35b5424aaeb9", + "memo": "877eab51bef6d9f956e53012ffbc61f2f41ee98472eb9b13c54ed57ab84b697e", "projects": [ { "name": "github.com/RobotsAndPencils/buford", @@ -157,7 +157,7 @@ { "name": "golang.org/x/crypto", "branch": "master", - "revision": "728b753d0135da6801d45a38e6f43ff55779c5c2", + "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7", "packages": [ "acme", "acme/autocert", diff --git a/manifest.json b/manifest.json index 45495a7e..f82c44b9 100644 --- a/manifest.json +++ b/manifest.json @@ -15,6 +15,9 @@ "github.com/groob/plist": { "branch": "master" }, + "github.com/micromdm/dep": { + "branch": "master" + }, "github.com/micromdm/mdm": { "branch": "master" }, diff --git a/serve.go b/serve.go index 19993321..413ffd3f 100644 --- a/serve.go +++ b/serve.go @@ -6,8 +6,10 @@ import ( "crypto/tls" "crypto/x509" "encoding/asn1" + "encoding/json" "encoding/pem" "flag" + "fmt" "io/ioutil" stdlog "log" "net/http" @@ -30,12 +32,14 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" + "github.com/micromdm/dep" boltdepot "github.com/micromdm/scep/depot/bolt" scep "github.com/micromdm/scep/server" "github.com/micromdm/nano/checkin" "github.com/micromdm/nano/command" "github.com/micromdm/nano/connect" + "github.com/micromdm/nano/depsync" "github.com/micromdm/nano/device" "github.com/micromdm/nano/enroll" "github.com/micromdm/nano/pubsub" @@ -85,6 +89,7 @@ func serve(args []string) error { sm.setupPushService() sm.setupCommandService() sm.setupCommandQueue() + sm.setupDEPSync() if sm.err != nil { stdlog.Fatal(sm.err) } @@ -427,6 +432,66 @@ func topicFromCert(cert *x509.Certificate) (string, error) { // the CA. const scepCACertName = "/var/db/micromdm/SCEPCACert.pem" +func (c *config) setupDEPSync() { + if c.err != nil { + return + } + + // depsim config + depsim := true + conf := &dep.Config{ + ConsumerKey: "CK_48dd68d198350f51258e885ce9a5c37ab7f98543c4a697323d75682a6c10a32501cb247e3db08105db868f73f2c972bdb6ae77112aea803b9219eb52689d42e6", + ConsumerSecret: "CS_34c7b2b531a600d99a0e4edcf4a78ded79b86ef318118c2f5bcfee1b011108c32d5302df801adbe29d446eb78f02b13144e323eb9aad51c79f01e50cb45c3a68", + AccessToken: "AT_927696831c59ba510cfe4ec1a69e5267c19881257d4bca2906a99d0785b785a6f6fdeb09774954fdd5e2d0ad952e3af52c6d8d2f21c924ba0caf4a031c158b89", + AccessSecret: "AS_c31afd7a09691d83548489336e8ff1cb11b82b6bca13f793344496a556b1f4972eaff4dde6deb5ac9cf076fdfa97ec97699c34d515947b9cf9ed31c99dded6ba", + } + + // try getting the oauth config from bolt + + err := c.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(depTokenBucket)) + if b == nil { + fmt.Println("no DEP server token found. using depsim") + return nil + } + _, v := b.Cursor().First() + if v == nil { + return nil + } + var token DEPTokenJSON + err := json.Unmarshal(v, &token) + if err != nil { + return err + } + conf.ConsumerSecret = token.ConsumerSecret + conf.ConsumerKey = token.ConsumerKey + conf.AccessSecret = token.AccessSecret + conf.AccessToken = token.AccessToken + // TODO handle expiration. + depsim = false + return nil + }) + if err != nil { + c.err = err + return + } + + depServerURL := "https://mdmenrollment.apple.com" + if depsim { + depServerURL = "http://dep.micromdm.io:9000" + } + client, err := dep.NewClient(conf, dep.ServerURL(depServerURL)) + if err != nil { + c.err = err + return + } + + _, c.err = depsync.New(client, c.pubclient) + if err != nil { + return + } +} + func (c *config) setupSCEP(logger log.Logger) { if c.err != nil { return