github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/track.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 "errors" 8 "fmt" 9 "time" 10 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 jsonw "github.com/keybase/go-jsonw" 13 ) 14 15 var ErrTrackingExpired = errors.New("Local track expired") 16 17 // Can be a ProofLinkWithState, one of the identities listed in a 18 // tracking statement, or a PGP Fingerprint! 19 type TrackIDComponent interface { 20 ToIDString() string 21 ToKeyValuePair() (string, string) 22 GetProofState() keybase1.ProofState 23 LastWriterWins() bool 24 GetProofType() keybase1.ProofType 25 } 26 27 type TrackSet struct { 28 ids map[string]TrackIDComponent 29 services map[string]bool 30 } 31 32 func NewTrackSet() *TrackSet { 33 return &TrackSet{ 34 ids: make(map[string]TrackIDComponent), 35 services: make(map[string]bool), 36 } 37 } 38 39 func (ts TrackSet) Add(t TrackIDComponent) { 40 ts.ids[t.ToIDString()] = t 41 if t.LastWriterWins() { 42 k, _ := t.ToKeyValuePair() 43 ts.services[k] = true 44 } 45 } 46 47 func (ts TrackSet) GetProofState(id string) keybase1.ProofState { 48 ret := keybase1.ProofState_NONE 49 if obj := ts.ids[id]; obj != nil { 50 ret = obj.GetProofState() 51 } 52 return ret 53 } 54 55 func (ts TrackSet) Subtract(b TrackSet) (out []TrackIDComponent) { 56 for _, c := range ts.ids { 57 if !b.HasMember(c) { 58 out = append(out, c) 59 } 60 } 61 return 62 } 63 64 func (ts TrackSet) HasMember(t TrackIDComponent) bool { 65 var found bool 66 67 // For LastWriterWins like social networks, then it just matters 68 // that there is some proof for the service. For non-last-writer-wins, 69 // like HTTPS and DNS, then the full proof needs to show up in A. 70 if t.LastWriterWins() { 71 k, _ := t.ToKeyValuePair() 72 _, found = ts.services[k] 73 } else { 74 _, found = ts.ids[t.ToIDString()] 75 } 76 return found 77 } 78 79 func (ts TrackSet) LenEq(b TrackSet) bool { 80 return len(ts.ids) == len(b.ids) 81 } 82 83 // ===================================================================== 84 85 type TrackInstructions struct { 86 Local bool 87 Remote bool 88 } 89 90 // ===================================================================== 91 92 type TrackSummary struct { 93 time time.Time 94 isRemote bool 95 username string 96 } 97 98 func (s TrackSummary) IsRemote() bool { return s.isRemote } 99 func (s TrackSummary) GetCTime() time.Time { return s.time } 100 func (s TrackSummary) Username() string { return s.username } 101 102 // ===================================================================== 103 104 type TrackLookup struct { 105 Contextified 106 link *TrackChainLink // The original chain link that I signed 107 set *TrackSet // The total set of tracked identities 108 ids map[string][]string // A http -> [foo.com, boo.com] lookup 109 trackerSeqno keybase1.Seqno // The seqno in the tracker's sighcain 110 } 111 112 func (l TrackLookup) ToSummary() TrackSummary { 113 ret := TrackSummary{ 114 time: l.GetCTime(), 115 isRemote: l.IsRemote(), 116 } 117 return ret 118 } 119 120 func (l TrackLookup) GetProofState(id string) keybase1.ProofState { 121 return l.set.GetProofState(id) 122 } 123 124 func (l TrackLookup) GetTrackerSeqno() keybase1.Seqno { 125 return l.trackerSeqno 126 } 127 128 func (l TrackLookup) GetTrackedKeys() []TrackedKey { 129 ret, err := l.link.GetTrackedKeys() 130 if err != nil { 131 l.G().Log.Warning("Error in lookup of tracked PGP fingerprints: %s", err) 132 } 133 return ret 134 } 135 136 func (l TrackLookup) GetEldestKID() keybase1.KID { 137 ret, err := l.link.GetEldestKID() 138 if err != nil { 139 l.G().Log.Warning("Error in lookup of eldest KID: %s", err) 140 } 141 return ret 142 } 143 144 func (l TrackLookup) GetTrackedLinkSeqno() keybase1.Seqno { 145 ret, err := l.link.GetTrackedLinkSeqno() 146 if err != nil { 147 l.G().Log.Warning("Error in lookup of tracked link's seqno: %s", err) 148 } 149 return ret 150 } 151 152 func (l TrackLookup) GetTmpExpireTime() (ret time.Time) { 153 return l.link.GetTmpExpireTime() 154 } 155 156 func (l TrackLookup) IsRemote() bool { 157 return l.link.IsRemote() 158 } 159 160 type TrackDiff interface { 161 BreaksTracking() bool 162 ToDisplayString() string 163 ToDisplayMarkup() *Markup 164 IsSameAsTracked() bool 165 GetTrackDiffType() keybase1.TrackDiffType 166 } 167 168 type TrackDiffUpgraded struct { 169 prev, curr string 170 } 171 172 func (t TrackDiffUpgraded) IsSameAsTracked() bool { 173 return false 174 } 175 176 func (t TrackDiffUpgraded) BreaksTracking() bool { 177 return false 178 } 179 func (t TrackDiffUpgraded) ToDisplayString() string { 180 return "Upgraded from " + t.prev + " to " + t.curr 181 } 182 func (t TrackDiffUpgraded) GetPrev() string { return t.prev } 183 func (t TrackDiffUpgraded) GetCurr() string { return t.curr } 184 func (t TrackDiffUpgraded) ToDisplayMarkup() *Markup { 185 return NewMarkup(t.ToDisplayString()) 186 } 187 func (t TrackDiffUpgraded) GetTrackDiffType() keybase1.TrackDiffType { 188 return keybase1.TrackDiffType_UPGRADED 189 } 190 191 type TrackDiffNone struct{} 192 193 func (t TrackDiffNone) BreaksTracking() bool { 194 return false 195 } 196 func (t TrackDiffNone) IsSameAsTracked() bool { 197 return true 198 } 199 200 func (t TrackDiffNone) ToDisplayString() string { 201 return "followed" 202 } 203 func (t TrackDiffNone) ToDisplayMarkup() *Markup { 204 return NewMarkup(t.ToDisplayString()) 205 } 206 func (t TrackDiffNone) GetTrackDiffType() keybase1.TrackDiffType { 207 return keybase1.TrackDiffType_NONE 208 } 209 210 type TrackDiffNoneViaTemporary struct{} 211 212 func (t TrackDiffNoneViaTemporary) BreaksTracking() bool { return false } 213 func (t TrackDiffNoneViaTemporary) IsSameAsTracked() bool { return true } 214 func (t TrackDiffNoneViaTemporary) ToDisplayString() string { return "snoozed" } 215 func (t TrackDiffNoneViaTemporary) ToDisplayMarkup() *Markup { return NewMarkup(t.ToDisplayString()) } 216 func (t TrackDiffNoneViaTemporary) GetTrackDiffType() keybase1.TrackDiffType { 217 return keybase1.TrackDiffType_NONE_VIA_TEMPORARY 218 } 219 220 type TrackDiffNew struct{} 221 222 func (t TrackDiffNew) BreaksTracking() bool { 223 return false 224 } 225 func (t TrackDiffNew) IsSameAsTracked() bool { 226 return false 227 } 228 229 type TrackDiffClash struct { 230 observed, expected string 231 } 232 233 func (t TrackDiffNew) ToDisplayString() string { 234 return "new" 235 } 236 func (t TrackDiffNew) ToDisplayMarkup() *Markup { 237 return NewMarkup(t.ToDisplayString()) 238 } 239 func (t TrackDiffNew) GetTrackDiffType() keybase1.TrackDiffType { 240 return keybase1.TrackDiffType_NEW 241 } 242 243 func (t TrackDiffClash) BreaksTracking() bool { 244 return true 245 } 246 247 func (t TrackDiffClash) ToDisplayString() string { 248 return "CHANGED from \"" + t.expected + "\"" 249 } 250 func (t TrackDiffClash) IsSameAsTracked() bool { 251 return false 252 } 253 func (t TrackDiffClash) ToDisplayMarkup() *Markup { 254 return NewMarkup(t.ToDisplayString()) 255 } 256 func (t TrackDiffClash) GetTrackDiffType() keybase1.TrackDiffType { 257 return keybase1.TrackDiffType_CLASH 258 } 259 260 type TrackDiffRevoked struct { 261 idc TrackIDComponent 262 } 263 264 func (t TrackDiffRevoked) BreaksTracking() bool { 265 return true 266 } 267 func (t TrackDiffRevoked) ToDisplayString() string { 268 return "Deleted proof: " + t.idc.ToIDString() 269 } 270 func (t TrackDiffRevoked) IsSameAsTracked() bool { 271 return false 272 } 273 func (t TrackDiffRevoked) ToDisplayMarkup() *Markup { 274 return NewMarkup(t.ToDisplayString()) 275 } 276 func (t TrackDiffRevoked) GetTrackDiffType() keybase1.TrackDiffType { 277 return keybase1.TrackDiffType_REVOKED 278 } 279 280 type TrackDiffSnoozedRevoked struct { 281 idc TrackIDComponent 282 } 283 284 func (t TrackDiffSnoozedRevoked) BreaksTracking() bool { 285 return false 286 } 287 func (t TrackDiffSnoozedRevoked) ToDisplayString() string { 288 return "Deleted proof: " + t.idc.ToIDString() + " (snoozed)" 289 } 290 func (t TrackDiffSnoozedRevoked) IsSameAsTracked() bool { 291 return true 292 } 293 func (t TrackDiffSnoozedRevoked) ToDisplayMarkup() *Markup { 294 return NewMarkup(t.ToDisplayString()) 295 } 296 func (t TrackDiffSnoozedRevoked) GetTrackDiffType() keybase1.TrackDiffType { 297 return keybase1.TrackDiffType_NONE_VIA_TEMPORARY 298 } 299 300 type TrackDiffRemoteFail struct { 301 observed keybase1.ProofState 302 } 303 304 func (t TrackDiffRemoteFail) BreaksTracking() bool { 305 return true 306 } 307 func (t TrackDiffRemoteFail) ToDisplayString() string { 308 return "remote failed" 309 } 310 func (t TrackDiffRemoteFail) ToDisplayMarkup() *Markup { 311 return NewMarkup(t.ToDisplayString()) 312 } 313 func (t TrackDiffRemoteFail) GetTrackDiffType() keybase1.TrackDiffType { 314 return keybase1.TrackDiffType_REMOTE_FAIL 315 } 316 func (t TrackDiffRemoteFail) IsSameAsTracked() bool { 317 return false 318 } 319 320 type TrackDiffRemoteWorking struct { 321 tracked keybase1.ProofState 322 } 323 324 func (t TrackDiffRemoteWorking) BreaksTracking() bool { 325 return false 326 } 327 func (t TrackDiffRemoteWorking) ToDisplayString() string { 328 return "newly working" 329 } 330 func (t TrackDiffRemoteWorking) ToDisplayMarkup() *Markup { 331 return NewMarkup(t.ToDisplayString()) 332 } 333 func (t TrackDiffRemoteWorking) GetTrackDiffType() keybase1.TrackDiffType { 334 return keybase1.TrackDiffType_REMOTE_WORKING 335 } 336 func (t TrackDiffRemoteWorking) IsSameAsTracked() bool { 337 return false 338 } 339 340 type TrackDiffRemoteChanged struct { 341 tracked, observed keybase1.ProofState 342 } 343 344 func (t TrackDiffRemoteChanged) BreaksTracking() bool { 345 return false 346 } 347 func (t TrackDiffRemoteChanged) ToDisplayString() string { 348 return "changed" 349 } 350 func (t TrackDiffRemoteChanged) ToDisplayMarkup() *Markup { 351 return NewMarkup(t.ToDisplayString()) 352 } 353 func (t TrackDiffRemoteChanged) GetTrackDiffType() keybase1.TrackDiffType { 354 return keybase1.TrackDiffType_REMOTE_CHANGED 355 } 356 func (t TrackDiffRemoteChanged) IsSameAsTracked() bool { 357 return false 358 } 359 360 type TrackDiffNewEldest struct { 361 tracked keybase1.KID 362 observed keybase1.KID 363 } 364 365 func (t TrackDiffNewEldest) BreaksTracking() bool { 366 return true 367 } 368 func (t TrackDiffNewEldest) IsSameAsTracked() bool { 369 return false 370 } 371 func (t TrackDiffNewEldest) GetTrackDiffType() keybase1.TrackDiffType { 372 return keybase1.TrackDiffType_NEW_ELDEST 373 } 374 func (t TrackDiffNewEldest) ToDisplayString() string { 375 if t.tracked.IsNil() { 376 return fmt.Sprintf("No key when followed; established new eldest key %s", t.observed) 377 } 378 if t.tracked.Equal(t.observed) { 379 return fmt.Sprintf("Account reset! Old key was %s; new key is the same", t.tracked) 380 } 381 return fmt.Sprintf("Account reset! Old key was %s; new key is %s", t.tracked, t.observed) 382 } 383 func (t TrackDiffNewEldest) ToDisplayMarkup() *Markup { 384 return NewMarkup(t.ToDisplayString()) 385 } 386 387 func NewTrackLookup(g *GlobalContext, link *TrackChainLink) *TrackLookup { 388 sbs := link.ToServiceBlocks() 389 set := NewTrackSet() 390 ids := make(map[string][]string) 391 for _, sb := range sbs { 392 set.Add(sb) 393 k, v := sb.ToKeyValuePair() 394 ids[k] = append(ids[k], v) 395 } 396 ret := &TrackLookup{Contextified: NewContextified(g), link: link, set: set, ids: ids, trackerSeqno: link.GetSeqno()} 397 return ret 398 } 399 400 func (l *TrackLookup) GetCTime() time.Time { 401 return l.link.GetCTime() 402 } 403 404 // ===================================================================== 405 406 func LocalTrackDBKey(tracker, trackee keybase1.UID, expireLocal bool) DbKey { 407 key := fmt.Sprintf("%s-%s", tracker, trackee) 408 if expireLocal { 409 key += "-expires" 410 } 411 return DbKey{Typ: DBLocalTrack, Key: key} 412 } 413 414 // ===================================================================== 415 416 func localTrackChainLinkFor(m MetaContext, tracker, trackee keybase1.UID, localExpires bool) (ret *TrackChainLink, err error) { 417 data, _, err := m.G().LocalDb.GetRaw(LocalTrackDBKey(tracker, trackee, localExpires)) 418 if err != nil { 419 m.Debug("| DB lookup failed") 420 return nil, err 421 } 422 if len(data) == 0 { 423 m.Debug("| No local track found") 424 return nil, nil 425 } 426 427 cl := &ChainLink{Contextified: NewContextified(m.G())} 428 if err = cl.UnpackLocal(data); err != nil { 429 m.Debug("| unpack local failed -> %s", err) 430 return nil, err 431 } 432 433 var linkETime time.Time 434 435 if localExpires { 436 linkETime = cl.GetCTime().Add(m.G().Env.GetLocalTrackMaxAge()) 437 438 m.Debug("| local track created %s, expires: %s, it is now %s", cl.GetCTime(), linkETime.String(), m.G().Clock().Now()) 439 440 if linkETime.Before(m.G().Clock().Now()) { 441 m.Debug("| expired local track, deleting") 442 _ = removeLocalTrack(m, tracker, trackee, true) 443 return nil, ErrTrackingExpired 444 } 445 } 446 447 base := GenericChainLink{cl} 448 ret, err = ParseTrackChainLink(base) 449 if ret != nil && err == nil { 450 ret.local = true 451 ret.tmpExpireTime = linkETime 452 } 453 454 return ret, err 455 } 456 457 func LocalTrackChainLinkFor(m MetaContext, tracker, trackee keybase1.UID) (ret *TrackChainLink, err error) { 458 return localTrackChainLinkFor(m, tracker, trackee, false) 459 } 460 461 func LocalTmpTrackChainLinkFor(m MetaContext, tracker, trackee keybase1.UID) (ret *TrackChainLink, err error) { 462 return localTrackChainLinkFor(m, tracker, trackee, true) 463 } 464 465 func StoreLocalTrack(m MetaContext, tracker keybase1.UID, trackee keybase1.UID, expiringLocal bool, statement *jsonw.Wrapper) error { 466 m.Debug("| StoreLocalTrack, expiring = %v", expiringLocal) 467 err := m.G().LocalDb.Put(LocalTrackDBKey(tracker, trackee, expiringLocal), nil, statement) 468 if err == nil { 469 m.G().IdentifyDispatch.NotifyTrackingSuccess(m, trackee) 470 } 471 return err 472 } 473 474 func removeLocalTrack(m MetaContext, tracker keybase1.UID, trackee keybase1.UID, expiringLocal bool) error { 475 m.Debug("| RemoveLocalTrack, expiring = %v", expiringLocal) 476 return m.G().LocalDb.Delete(LocalTrackDBKey(tracker, trackee, expiringLocal)) 477 } 478 479 func RemoveLocalTracks(m MetaContext, tracker keybase1.UID, trackee keybase1.UID) error { 480 e1 := removeLocalTrack(m, tracker, trackee, false) 481 e2 := removeLocalTrack(m, tracker, trackee, true) 482 return PickFirstError(e1, e2) 483 }