github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/device.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package libkb
     5  
     6  import (
     7  	"time"
     8  
     9  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    10  	jsonw "github.com/keybase/go-jsonw"
    11  )
    12  
    13  const (
    14  	DeviceIDLen    = 16
    15  	DeviceIDSuffix = 0x18
    16  )
    17  
    18  func NewDeviceID() (keybase1.DeviceID, error) {
    19  	var b []byte
    20  	b, err := RandBytes(DeviceIDLen)
    21  	if err != nil {
    22  		return "", err
    23  	}
    24  	b[DeviceIDLen-1] = DeviceIDSuffix
    25  	return keybase1.DeviceIDFromSlice(b)
    26  }
    27  
    28  type DeviceStatus struct {
    29  	Provisioned  bool
    30  	Keyed        bool
    31  	KeyAvailable bool
    32  }
    33  
    34  type Device struct {
    35  	ID          keybase1.DeviceID     `json:"id"`
    36  	Kid         keybase1.KID          `json:"kid,omitempty"`
    37  	Description *string               `json:"name,omitempty"`
    38  	Status      *int                  `json:"status,omitempty"`
    39  	Type        keybase1.DeviceTypeV2 `json:"type"`
    40  	CTime       keybase1.Time         `json:"ctime"`
    41  	MTime       keybase1.Time         `json:"mtime"`
    42  }
    43  
    44  type DeviceWithDeviceNumber struct {
    45  	*Device
    46  	DeviceNumberOfType int
    47  }
    48  
    49  // NewPaperDevice creates a new paper backup key device
    50  func NewPaperDevice(passphrasePrefix string) (*Device, error) {
    51  	did, err := NewDeviceID()
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	s := DeviceStatusActive
    56  	desc := passphrasePrefix
    57  
    58  	d := &Device{
    59  		ID:          did,
    60  		Type:        keybase1.DeviceTypeV2_PAPER,
    61  		Status:      &s,
    62  		Description: &desc,
    63  	}
    64  	return d, nil
    65  }
    66  
    67  func ParseDevice(jw *jsonw.Wrapper, t time.Time) (ret *Device, err error) {
    68  	var obj Device
    69  	if err = jw.UnmarshalAgain(&obj); err == nil {
    70  		ret = &obj
    71  		ret.CTime = keybase1.ToTime(t)
    72  		ret.MTime = keybase1.ToTime(t)
    73  	}
    74  	return
    75  }
    76  
    77  func (d *Device) Merge(d2 *Device) {
    78  	d.Type = d2.Type
    79  	if d2.Kid.Exists() {
    80  		d.Kid = d2.Kid
    81  	}
    82  	if d2.Description != nil {
    83  		d.Description = d2.Description
    84  	}
    85  	if d2.Status != nil {
    86  		d.Status = d2.Status
    87  	}
    88  	if d2.CTime.Before(d.CTime) && !d2.CTime.IsZero() {
    89  		d.CTime = d2.CTime
    90  	}
    91  	if d2.MTime.After(d.MTime) || d.MTime.IsZero() {
    92  		d.MTime = d2.MTime
    93  	}
    94  }
    95  
    96  func (d *Device) Export(lt LinkType) (*jsonw.Wrapper, error) {
    97  	dw, err := jsonw.NewObjectWrapper(d)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	if lt == LinkType(DelegationTypeSubkey) {
   103  		// subkeys shouldn't have name or type
   104  		if err := dw.DeleteKey("name"); err != nil {
   105  			return nil, err
   106  		}
   107  		if err := dw.DeleteKey("type"); err != nil {
   108  			return nil, err
   109  		}
   110  	}
   111  
   112  	// These were being set to 0, so don't include them
   113  	err = dw.DeleteKey("mtime")
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	err = dw.DeleteKey("ctime")
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	return dw, nil
   123  }
   124  
   125  func (d *Device) ProtExport() *keybase1.Device {
   126  	ex := &keybase1.Device{
   127  		Type:     d.Type,
   128  		DeviceID: d.ID,
   129  		CTime:    d.CTime,
   130  		MTime:    d.MTime,
   131  	}
   132  	if d.Description != nil {
   133  		ex.Name = *d.Description
   134  	}
   135  	if d.Status != nil {
   136  		ex.Status = *d.Status
   137  	}
   138  	if d.Kid.Exists() {
   139  		ex.VerifyKey = d.Kid
   140  	}
   141  	return ex
   142  }
   143  
   144  func (d DeviceWithDeviceNumber) ProtExportWithDeviceNum() *keybase1.Device {
   145  	ex := &keybase1.Device{
   146  		Type:               d.Type,
   147  		DeviceID:           d.ID,
   148  		CTime:              d.CTime,
   149  		MTime:              d.MTime,
   150  		DeviceNumberOfType: d.DeviceNumberOfType,
   151  	}
   152  	if d.Description != nil {
   153  		ex.Name = *d.Description
   154  	}
   155  	if d.Status != nil {
   156  		ex.Status = *d.Status
   157  	}
   158  	if d.Kid.Exists() {
   159  		ex.VerifyKey = d.Kid
   160  	}
   161  	return ex
   162  }
   163  
   164  func (d *Device) IsActive() bool {
   165  	if d.Status == nil {
   166  		return false
   167  	}
   168  	return *d.Status == DeviceStatusActive
   169  }
   170  
   171  func (d *Device) StatusString() string {
   172  	return DeviceStatusToString(d.Status)
   173  }
   174  
   175  func DeviceStatusToString(i *int) string {
   176  	if i == nil {
   177  		return "<nil>"
   178  	}
   179  	switch *i {
   180  	case DeviceStatusNone:
   181  		return "none"
   182  	case DeviceStatusActive:
   183  		return "active"
   184  	case DeviceStatusDefunct:
   185  		return "revoked"
   186  	}
   187  	return "unknown"
   188  }