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 }