github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/protocol/gregor1/extras.go (about) 1 package gregor1 2 3 import ( 4 "crypto/sha256" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "strings" 9 "time" 10 11 "bytes" 12 13 "github.com/keybase/client/go/gregor" 14 "github.com/keybase/go-codec/codec" 15 ) 16 17 func (u UID) Bytes() []byte { return []byte(u) } 18 func (u UID) String() string { return hex.EncodeToString(u) } 19 func (u UID) Eq(other UID) bool { return bytes.Equal(u.Bytes(), other.Bytes()) } 20 func (u UID) IsNil() bool { return len(u) == 0 } 21 22 func UIDPtrEq(x, y *UID) bool { 23 if x != nil && y != nil { 24 return (*x).Eq(*y) 25 } 26 return (x == nil) && (y == nil) 27 } 28 29 func (d DeviceID) Bytes() []byte { return []byte(d) } 30 func (d DeviceID) String() string { return hex.EncodeToString(d) } 31 func (d DeviceID) Eq(other DeviceID) bool { 32 return bytes.Equal(d.Bytes(), other.Bytes()) 33 } 34 func (m MsgID) Bytes() []byte { return []byte(m) } 35 func (m MsgID) String() string { return hex.EncodeToString(m) } 36 func (m MsgID) Eq(n MsgID) bool { return m.String() == n.String() } 37 func (s System) String() string { return string(s) } 38 func (c Category) String() string { return string(c) } 39 func (b Body) Bytes() []byte { return []byte(b) } 40 func (c Category) Eq(c2 Category) bool { return string(c) == string(c2) } 41 func (c Category) HasPrefix(c2 Category) bool { return strings.HasPrefix(string(c), string(c2)) } 42 43 func (t TimeOrOffset) Time() *time.Time { 44 if t.Time_.IsZero() { 45 return nil 46 } 47 ret := FromTime(t.Time_) 48 return &ret 49 } 50 func (t TimeOrOffset) Offset() *time.Duration { 51 if t.Offset_ == 0 { 52 return nil 53 } 54 d := time.Duration(t.Offset_) * time.Millisecond 55 return &d 56 } 57 func (t TimeOrOffset) IsZero() bool { 58 return t.Time_.IsZero() && t.Offset_ == 0 59 } 60 61 func (t TimeOrOffset) Before(t2 time.Time) bool { 62 if t.Time() != nil { 63 return t.Time().Before(t2) 64 } 65 if t.Offset() != nil { 66 return time.Now().Add(*t.Offset()).Before(t2) 67 } 68 return false 69 } 70 71 func (s StateSyncMessage) Metadata() gregor.Metadata { 72 return s.Md_ 73 } 74 75 func (m MsgRange) EndTime() gregor.TimeOrOffset { 76 return m.EndTime_ 77 } 78 func (m MsgRange) Category() gregor.Category { 79 return m.Category_ 80 } 81 func (m MsgRange) SkipMsgIDs() (res []gregor.MsgID) { 82 for _, s := range m.SkipMsgIDs_ { 83 res = append(res, s) 84 } 85 return res 86 } 87 88 func (d Dismissal) RangesToDismiss() []gregor.MsgRange { 89 var ret []gregor.MsgRange 90 for _, r := range d.Ranges_ { 91 ret = append(ret, r) 92 } 93 return ret 94 } 95 96 func (d Dismissal) MsgIDsToDismiss() []gregor.MsgID { 97 var ret []gregor.MsgID 98 for _, m := range d.MsgIDs_ { 99 ret = append(ret, m) 100 } 101 return ret 102 } 103 104 func (m Metadata) CTime() time.Time { return FromTime(m.Ctime_) } 105 func (m Metadata) UID() gregor.UID { 106 if m.Uid_ == nil { 107 return nil 108 } 109 return m.Uid_ 110 } 111 func (m Metadata) MsgID() gregor.MsgID { 112 if m.MsgID_ == nil { 113 return nil 114 } 115 return m.MsgID_ 116 } 117 func (m Metadata) DeviceID() gregor.DeviceID { 118 if m.DeviceID_ == nil { 119 return nil 120 } 121 return m.DeviceID_ 122 } 123 func (m Metadata) InBandMsgType() gregor.InBandMsgType { return gregor.InBandMsgType(m.InBandMsgType_) } 124 125 func (m Metadata) String() string { 126 return fmt.Sprintf("[ CTime: %s Type: %d ID: %s UID: %s ]", m.CTime(), 127 m.InBandMsgType(), m.MsgID(), m.UID()) 128 } 129 130 func (i ItemAndMetadata) Metadata() gregor.Metadata { 131 if i.Md_ == nil { 132 return nil 133 } 134 return i.Md_ 135 } 136 func (i ItemAndMetadata) Body() gregor.Body { 137 if i.Item_.Body_ == nil { 138 return nil 139 } 140 return i.Item_.Body_ 141 } 142 func (i ItemAndMetadata) Category() gregor.Category { 143 if i.Item_.Category_ == "" { 144 return nil 145 } 146 return i.Item_.Category_ 147 } 148 func (i ItemAndMetadata) DTime() gregor.TimeOrOffset { 149 var unset TimeOrOffset 150 if i.Item_.Dtime_ == unset { 151 return nil 152 } 153 return i.Item_.Dtime_ 154 } 155 func (i ItemAndMetadata) RemindTimes() []gregor.TimeOrOffset { 156 var ret []gregor.TimeOrOffset 157 for _, t := range i.Item_.RemindTimes_ { 158 ret = append(ret, t) 159 } 160 return ret 161 } 162 163 func (i ItemAndMetadata) String() string { 164 rts := "[ " 165 for _, rt := range i.RemindTimes() { 166 rts += fmt.Sprintf("[%s,%s]", rt.Time(), rt.Offset()) 167 } 168 rts += "]" 169 return fmt.Sprintf("MD: %s Cat: %s DTime: %s RTs: %s Body: %s", i.Metadata(), 170 i.Category(), i.DTime(), rts, i.Body()) 171 } 172 173 func (s StateUpdateMessage) Metadata() gregor.Metadata { return s.Md_ } 174 func (s StateUpdateMessage) Creation() gregor.Item { 175 if s.Creation_ == nil { 176 return nil 177 } 178 return ItemAndMetadata{Md_: &s.Md_, Item_: s.Creation_} 179 } 180 func (s StateUpdateMessage) Dismissal() gregor.Dismissal { 181 if s.Dismissal_ == nil { 182 return nil 183 } 184 return s.Dismissal_ 185 } 186 187 func (i InBandMessage) Merge(i2 gregor.InBandMessage) (res gregor.InBandMessage, err error) { 188 t2, ok := i2.(InBandMessage) 189 if !ok { 190 return res, fmt.Errorf("bad merge; wrong type: %T", i2) 191 } 192 if i.StateSync_ != nil || t2.StateSync_ != nil { 193 return res, errors.New("Cannot merge sync messages") 194 } 195 st, err := i.StateUpdate_.Merge(t2.StateUpdate_) 196 if err != nil { 197 return res, err 198 } 199 return InBandMessage{StateUpdate_: &st}, nil 200 } 201 202 func (s StateUpdateMessage) Merge(s2 *StateUpdateMessage) (res StateUpdateMessage, err error) { 203 if s.Creation_ != nil && s2.Creation_ != nil { 204 return res, errors.New("cannot merge two creation messages") 205 } 206 res.Md_ = s.Md_ 207 res.Creation_ = s.Creation_ 208 if res.Creation_ == nil { 209 res.Creation_ = s2.Creation_ 210 } 211 res.Dismissal_ = s.Dismissal_ 212 if res.Dismissal_ == nil { 213 res.Dismissal_ = s2.Dismissal_ 214 } else if res.Dismissal_ != nil && s2.Dismissal_ != nil { 215 res.Dismissal_.MsgIDs_ = append(res.Dismissal_.MsgIDs_, s2.Dismissal_.MsgIDs_...) 216 res.Dismissal_.Ranges_ = append(res.Dismissal_.Ranges_, s2.Dismissal_.Ranges_...) 217 } 218 return res, nil 219 } 220 221 func (i InBandMessage) Metadata() gregor.Metadata { 222 if i.StateUpdate_ != nil { 223 return i.StateUpdate_.Md_ 224 } 225 if i.StateSync_ != nil { 226 return i.StateSync_.Md_ 227 } 228 return nil 229 } 230 231 func (i InBandMessage) ToStateSyncMessage() gregor.StateSyncMessage { 232 if i.StateSync_ == nil { 233 return nil 234 } 235 return i.StateSync_ 236 } 237 238 func (i InBandMessage) ToStateUpdateMessage() gregor.StateUpdateMessage { 239 if i.StateUpdate_ == nil { 240 return nil 241 } 242 return i.StateUpdate_ 243 } 244 245 func (o OutOfBandMessage) Body() gregor.Body { 246 if o.Body_ == nil { 247 return nil 248 } 249 return o.Body_ 250 } 251 func (o OutOfBandMessage) System() gregor.System { 252 if o.System_ == "" { 253 return nil 254 } 255 return o.System_ 256 } 257 func (o OutOfBandMessage) UID() gregor.UID { 258 if o.Uid_ == nil { 259 return nil 260 } 261 return o.Uid_ 262 } 263 264 func (m Message) ToInBandMessage() gregor.InBandMessage { 265 if m.Ibm_ == nil { 266 return nil 267 } 268 return *m.Ibm_ 269 } 270 271 func (m Message) ToOutOfBandMessage() gregor.OutOfBandMessage { 272 if m.Oobm_ == nil { 273 return nil 274 } 275 return *m.Oobm_ 276 } 277 278 func (m Message) Marshal() ([]byte, error) { 279 var b []byte 280 err := codec.NewEncoderBytes(&b, &codec.MsgpackHandle{WriteExt: true}).Encode(m) 281 return b, err 282 } 283 284 func (m *Message) SetCTime(ctime time.Time) { 285 if m.Ibm_ != nil && m.Ibm_.StateUpdate_ != nil { 286 m.Ibm_.StateUpdate_.Md_.Ctime_ = ToTime(ctime) 287 } 288 } 289 290 func (m *Message) SetUID(uid UID) error { 291 if m.Ibm_ != nil { 292 if m.Ibm_.StateUpdate_ != nil { 293 m.Ibm_.StateUpdate_.Md_.Uid_ = uid 294 return nil 295 } 296 if m.Ibm_.StateSync_ != nil { 297 m.Ibm_.StateSync_.Md_.Uid_ = uid 298 return nil 299 } 300 return errors.New("unable to set uid on inband message (no StatUpdate or StateSync)") 301 } 302 if m.Oobm_ != nil { 303 m.Oobm_.Uid_ = uid 304 return nil 305 } 306 307 return errors.New("unable to set uid (no inband or out-of-band message)") 308 } 309 310 func (r Reminder) Item() gregor.Item { return r.Item_ } 311 func (r Reminder) RemindTime() time.Time { return FromTime(r.RemindTime_) } 312 func (r Reminder) Seqno() int { return r.Seqno_ } 313 314 func (r ReminderID) UID() gregor.UID { return r.Uid_ } 315 func (r ReminderID) MsgID() gregor.MsgID { return r.MsgID_ } 316 func (r ReminderID) Seqno() int { return r.Seqno_ } 317 318 func (s State) Size() int { 319 return len(s.Items_) 320 } 321 322 func (s State) Items() ([]gregor.Item, error) { 323 ret := make([]gregor.Item, 0, len(s.Items_)) 324 for _, i := range s.Items_ { 325 ret = append(ret, i) 326 } 327 return ret, nil 328 } 329 330 func (s State) GetItem(msgID gregor.MsgID) (gregor.Item, bool) { 331 for _, i := range s.Items_ { 332 if i.Metadata().MsgID().String() == msgID.String() { 333 return i, true 334 } 335 } 336 return nil, false 337 } 338 339 func (s State) Marshal() ([]byte, error) { 340 var b []byte 341 err := codec.NewEncoderBytes(&b, &codec.MsgpackHandle{WriteExt: true}).Encode(s) 342 return b, err 343 } 344 345 func (s State) Hash() ([]byte, error) { 346 b, err := s.Marshal() 347 if err != nil { 348 return nil, err 349 } 350 351 sum := sha256.Sum256(b) 352 return sum[:], nil 353 } 354 355 func (s State) Export() (gregor.ProtocolState, error) { 356 return s, nil 357 } 358 359 func (s State) ProtocolName() string { 360 return "gregor.1" 361 } 362 363 func (i ItemAndMetadata) InCategory(c Category) bool { 364 return i.Item_.Category_.Eq(c) 365 } 366 367 func (i ItemAndMetadata) HasCategoryPrefix(c Category) bool { 368 return i.Item_.Category_.HasPrefix(c) 369 } 370 371 func (s State) ItemsInCategory(gc gregor.Category) ([]gregor.Item, error) { 372 var ret []gregor.Item 373 c := Category(gc.String()) 374 for _, i := range s.Items_ { 375 if i.InCategory(c) { 376 ret = append(ret, i) 377 } 378 } 379 return ret, nil 380 } 381 382 func (s State) ItemsWithCategoryPrefix(gc gregor.Category) ([]gregor.Item, error) { 383 var ret []gregor.Item 384 c := Category(gc.String()) 385 for _, i := range s.Items_ { 386 if i.HasCategoryPrefix(c) { 387 ret = append(ret, i) 388 } 389 } 390 return ret, nil 391 } 392 393 func FromTime(t Time) time.Time { 394 if t == 0 { 395 return time.Time{} 396 } 397 return time.Unix(0, int64(t)*1000000) 398 } 399 400 func (t Time) Time() time.Time { 401 return FromTime(t) 402 } 403 404 func (t Time) UnixSeconds() int64 { 405 return t.Time().Unix() 406 } 407 408 func (t Time) UnixMilliseconds() int64 { 409 return t.Time().UnixNano() / 1e6 410 } 411 412 func (t Time) UnixMicroseconds() int64 { 413 return t.Time().UnixNano() / 1e3 414 } 415 416 // copied from keybase/client/go/protocol/extras.go. Consider eventually a 417 // refactor to allow this code to be shared. 418 func ToTime(t time.Time) Time { 419 // the result of calling UnixNano on the zero Time is undefined. 420 // https://golang.org/pkg/time/#Time.UnixNano 421 if t.IsZero() { 422 return 0 423 } 424 return Time(t.UnixNano() / 1000000) 425 } 426 427 func TimeFromSeconds(seconds int64) Time { 428 return Time(seconds * 1000) 429 } 430 431 func TimeFromMilliseconds(ms int64) Time { 432 return Time(ms) 433 } 434 435 func (t Time) IsZero() bool { return t == 0 } 436 func (t Time) After(t2 Time) bool { return t > t2 } 437 func (t Time) Before(t2 Time) bool { return t < t2 } 438 439 func FormatTime(t Time) string { 440 layout := "2006-01-02 15:04:05 MST" 441 return FromTime(t).Format(layout) 442 } 443 444 func ToDurationMsec(d time.Duration) DurationMsec { 445 return DurationMsec(d / time.Millisecond) 446 } 447 448 func (d DurationMsec) ToDuration() time.Duration { 449 return time.Duration(d) * time.Millisecond 450 } 451 452 func ToDurationSec(d time.Duration) DurationSec { 453 return DurationSec(d / time.Second) 454 } 455 456 func (d DurationSec) ToDuration() time.Duration { 457 return time.Duration(d) * time.Second 458 } 459 460 // DeviceID returns the deviceID in a SyncArc, or interface nil 461 // (and not gregor1.DeviceID(nil)) if not was specified. 462 func (s SyncArg) DeviceID() gregor.DeviceID { 463 if s.Deviceid == nil { 464 return nil 465 } 466 return s.Deviceid 467 } 468 469 // UID returns the UID in a SyncArc, or interface nil 470 // (and not gregor1.UID(nil)) if not was specified. 471 func (s SyncArg) UID() gregor.UID { 472 if s.Uid == nil { 473 return nil 474 } 475 return s.Uid 476 } 477 478 func (s SyncArg) CTime() time.Time { 479 return FromTime(s.Ctime) 480 } 481 482 func (r ReminderSet) Reminders() []gregor.Reminder { 483 var out []gregor.Reminder 484 for _, reminder := range r.Reminders_ { 485 out = append(out, reminder) 486 } 487 return out 488 } 489 490 func (r ReminderSet) MoreRemindersReady() bool { return r.MoreRemindersReady_ } 491 492 func UIDListContains(list []UID, x UID) bool { 493 for _, y := range list { 494 if x.String() == y.String() { 495 return true 496 } 497 } 498 return false 499 } 500 501 // Merge two lists of UIDs. Duplicates will be dropped. Not stably ordered. 502 func UIDListMerge(list1 []UID, list2 []UID) []UID { 503 m := make(map[string]UID) 504 for _, uid := range list1 { 505 m[uid.String()] = uid 506 } 507 for _, uid := range list2 { 508 m[uid.String()] = uid 509 } 510 res := make([]UID, 0) 511 for _, uid := range m { 512 res = append(res, uid) 513 } 514 return res 515 } 516 517 var _ gregor.UID = UID{} 518 var _ gregor.MsgID = MsgID{} 519 var _ gregor.DeviceID = DeviceID{} 520 var _ gregor.System = System("") 521 var _ gregor.Body = Body{} 522 var _ gregor.Category = Category("") 523 var _ gregor.TimeOrOffset = TimeOrOffset{} 524 var _ gregor.Metadata = Metadata{} 525 var _ gregor.StateSyncMessage = StateSyncMessage{} 526 var _ gregor.MsgRange = MsgRange{} 527 var _ gregor.Dismissal = Dismissal{} 528 var _ gregor.Item = ItemAndMetadata{} 529 var _ gregor.Reminder = Reminder{} 530 var _ gregor.StateUpdateMessage = StateUpdateMessage{} 531 var _ gregor.InBandMessage = InBandMessage{} 532 var _ gregor.OutOfBandMessage = OutOfBandMessage{} 533 var _ gregor.Message = Message{} 534 var _ gregor.State = State{} 535 var _ gregor.ReminderID = ReminderID{} 536 var _ gregor.ReminderSet = ReminderSet{}