diff --git a/storage/mysql/bstoken.go b/storage/mysql/bstoken.go index 61ad067..f21e150 100644 --- a/storage/mysql/bstoken.go +++ b/storage/mysql/bstoken.go @@ -11,7 +11,10 @@ func (s *MySQLStorage) StoreBootstrapToken(r *mdm.Request, msg *mdm.SetBootstrap nullEmptyString(msg.BootstrapToken.BootstrapToken.String()), r.ID, ) - return err + if err != nil { + return err + } + return s.updateLastSeen(r) } func (s *MySQLStorage) RetrieveBootstrapToken(r *mdm.Request, _ *mdm.GetBootstrapToken) (*mdm.BootstrapToken, error) { @@ -26,5 +29,8 @@ func (s *MySQLStorage) RetrieveBootstrapToken(r *mdm.Request, _ *mdm.GetBootstra } bsToken := new(mdm.BootstrapToken) err = bsToken.SetTokenString(tokenB64) + if err == nil { + err = s.updateLastSeen(r) + } return bsToken, err } diff --git a/storage/mysql/mysql.go b/storage/mysql/mysql.go index 0132fcd..ad78de6 100644 --- a/storage/mysql/mysql.go +++ b/storage/mysql/mysql.go @@ -5,6 +5,7 @@ import ( "context" "database/sql" "errors" + "fmt" "github.com/micromdm/nanomdm/cryptoutil" "github.com/micromdm/nanomdm/log" @@ -165,9 +166,9 @@ func (s *MySQLStorage) StoreTokenUpdate(r *mdm.Request, msg *mdm.TokenUpdate) er _, err = s.db.ExecContext( r.Context, ` INSERT INTO enrollments - (id, device_id, user_id, type, topic, push_magic, token_hex, token_update_tally) + (id, device_id, user_id, type, topic, push_magic, token_hex, last_seen_at, token_update_tally) VALUES - (?, ?, ?, ?, ?, ?, ?, 1) AS new + (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, 1) AS new ON DUPLICATE KEY UPDATE device_id = new.device_id, @@ -177,6 +178,7 @@ UPDATE push_magic = new.push_magic, token_hex = new.token_hex, enabled = 1, + last_seen_at = CURRENT_TIMESTAMP, enrollments.token_update_tally = enrollments.token_update_tally + 1;`, r.ID, deviceId, @@ -227,17 +229,33 @@ UPDATE nullEmptyString(msg.UserLongName), msg.Raw, ) - return err + if err != nil { + return err + } + return s.updateLastSeen(r) } +// Disable can be called for an Authenticate or CheckOut message func (s *MySQLStorage) Disable(r *mdm.Request) error { if r.ParentID != "" { return errors.New("can only disable a device channel") } _, err := s.db.ExecContext( r.Context, - `UPDATE enrollments SET enabled = 0, token_update_tally = 0 WHERE device_id = ? AND enabled = 1;`, + `UPDATE enrollments SET enabled = 0, token_update_tally = 0, last_seen_at = CURRENT_TIMESTAMP WHERE device_id = ? AND enabled = 1;`, r.ID, ) return err } + +func (s *MySQLStorage) updateLastSeen(r *mdm.Request) (err error) { + _, err = s.db.ExecContext( + r.Context, + `UPDATE enrollments SET last_seen_at = CURRENT_TIMESTAMP WHERE id = ?`, + r.ID, + ) + if err != nil { + err = fmt.Errorf("updating last seen: %w", err) + } + return +} diff --git a/storage/mysql/queue.go b/storage/mysql/queue.go index d485517..4e556fc 100644 --- a/storage/mysql/queue.go +++ b/storage/mysql/queue.go @@ -48,8 +48,10 @@ func (m *MySQLStorage) EnqueueCommand(ctx context.Context, ids []string, cmd *md } func (s *MySQLStorage) StoreCommandReport(r *mdm.Request, result *mdm.CommandResults) error { + if err := s.updateLastSeen(r); err != nil { + return err + } if result.Status == "Idle" { - // TODO: store LastSeen? return nil } notNowConstants := "NULL, 0" diff --git a/storage/mysql/schema.00008.sql b/storage/mysql/schema.00008.sql new file mode 100644 index 0000000..82596a8 --- /dev/null +++ b/storage/mysql/schema.00008.sql @@ -0,0 +1 @@ +ALTER TABLE enrollments ADD COLUMN last_seen_at TIMESTAMP NOT NULL; diff --git a/storage/mysql/schema.sql b/storage/mysql/schema.sql index 8a5d603..e870875 100644 --- a/storage/mysql/schema.sql +++ b/storage/mysql/schema.sql @@ -102,6 +102,8 @@ CREATE TABLE enrollments ( enabled BOOLEAN NOT NULL DEFAULT 1, token_update_tally INTEGER NOT NULL DEFAULT 1, + last_seen_at TIMESTAMP NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,