github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/remote_proof_links.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  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
     8  	jsonw "github.com/keybase/go-jsonw"
     9  )
    10  
    11  // RemoteProofLinks holds a set of RemoteProofChainLinks,
    12  // organized by service.
    13  type RemoteProofLinks struct {
    14  	Contextified
    15  	links map[string][]ProofLinkWithState
    16  }
    17  
    18  // ProofLinkWithState contains a RemoteProofChainLink and the
    19  // proof state.  In addition, it satisfies the TrackIdComponent interface.
    20  type ProofLinkWithState struct {
    21  	link  RemoteProofChainLink
    22  	state keybase1.ProofState
    23  }
    24  
    25  // NewRemoteProofLinks creates a new empty collection of proof
    26  // links.
    27  func NewRemoteProofLinks(g *GlobalContext) *RemoteProofLinks {
    28  	return &RemoteProofLinks{
    29  		Contextified: NewContextified(g),
    30  		links:        make(map[string][]ProofLinkWithState),
    31  	}
    32  }
    33  
    34  // Insert adds a link to the collection of proof links.
    35  func (r *RemoteProofLinks) Insert(link RemoteProofChainLink, err ProofError) {
    36  	key := link.TableKey()
    37  	if len(key) == 0 {
    38  		return
    39  	}
    40  	r.links[key] = append(r.links[key], ProofLinkWithState{link: link, state: ProofErrorToState(err)})
    41  }
    42  
    43  // ForService returns all the active proof links for a service.
    44  func (r *RemoteProofLinks) ForService(st ServiceType) []RemoteProofChainLink {
    45  	var links []RemoteProofChainLink
    46  	for _, linkWithState := range r.links[st.Key()] {
    47  		if linkWithState.link.LastWriterWins() {
    48  			// Clear the array if it's a last-writer wins service.
    49  			// (like many social networks)
    50  			links = nil
    51  		}
    52  		if linkWithState.link.IsRevoked() {
    53  			continue
    54  		}
    55  		links = append(links, linkWithState.link)
    56  	}
    57  	return links
    58  }
    59  
    60  // Active returns all the active proof links, deduplicating any and
    61  // honoring the LastWriterWins option.
    62  func (r *RemoteProofLinks) Active() []RemoteProofChainLink {
    63  	a := r.active()
    64  	links := make([]RemoteProofChainLink, len(a))
    65  	for i, b := range a {
    66  		links[i] = b.link
    67  	}
    68  	return links
    69  }
    70  
    71  // TrackingStatement generates the remote proofs portions of the
    72  // tracking statement from the active proofs.
    73  func (r *RemoteProofLinks) TrackingStatement() *jsonw.Wrapper {
    74  	var proofs []*jsonw.Wrapper
    75  	for _, x := range r.active() {
    76  		d, err := x.link.ToTrackingStatement(x.state)
    77  		if err != nil {
    78  			r.G().Log.Warning("Problem with a proof: %s", err)
    79  			continue
    80  		}
    81  		if d != nil {
    82  			proofs = append(proofs, d)
    83  		}
    84  	}
    85  
    86  	res := jsonw.NewArray(len(proofs))
    87  	for i, proof := range proofs {
    88  		_ = res.SetIndex(i, proof)
    89  	}
    90  	return res
    91  }
    92  
    93  // TrackSet creates a new TrackSet with all the active proofs.
    94  func (r *RemoteProofLinks) TrackSet() *TrackSet {
    95  	ret := NewTrackSet()
    96  	for _, ap := range r.active() {
    97  		ret.Add(ap)
    98  	}
    99  	return ret
   100  }
   101  
   102  // AddProofsToSet adds the active proofs to an existing ProofSet, if they're one of the
   103  // given OkStates. If okStates is nil, then we check only against keybase1.ProofState_OK.
   104  func (r *RemoteProofLinks) AddProofsToSet(existing *ProofSet, okStates []keybase1.ProofState) {
   105  	if okStates == nil {
   106  		okStates = []keybase1.ProofState{keybase1.ProofState_OK}
   107  	}
   108  	isOkState := func(s1 keybase1.ProofState) bool {
   109  		for _, s2 := range okStates {
   110  			if s1 == s2 {
   111  				return true
   112  			}
   113  		}
   114  		return false
   115  	}
   116  	for _, a := range r.active() {
   117  		if !isOkState(a.state) {
   118  			continue
   119  		}
   120  		AddToProofSetNoChecks(a.link, existing)
   121  	}
   122  }
   123  
   124  func RemoteProofChainLinkToProof(r RemoteProofChainLink) Proof {
   125  	k, v := r.ToKeyValuePair()
   126  	return Proof{Key: k, Value: v}
   127  }
   128  
   129  func AddToProofSetNoChecks(r RemoteProofChainLink, ps *ProofSet) {
   130  	ps.Add(RemoteProofChainLinkToProof(r))
   131  }
   132  
   133  func (r *RemoteProofLinks) active() []ProofLinkWithState {
   134  	var links []ProofLinkWithState
   135  	seen := make(map[string]bool)
   136  
   137  	// Loop over all types of services
   138  	for _, list := range r.links {
   139  
   140  		// Loop over all proofs for that type, from most recent,
   141  		// to oldest.
   142  		for i := len(list) - 1; i >= 0; i-- {
   143  			both := list[i]
   144  			link := both.link
   145  			id := CanonicalProofName(link)
   146  
   147  			if !link.IsRevoked() && !seen[id] {
   148  				links = append(links, both)
   149  			}
   150  
   151  			// We only want to use the last proof in the list
   152  			// if we have several (like for dns://chriscoyne.com)
   153  			seen[id] = true
   154  
   155  			// Things like Twitter, Github, etc, are last-writer wins.
   156  			// Things like dns/https can have multiples
   157  			if link.LastWriterWins() {
   158  				break
   159  			}
   160  		}
   161  	}
   162  	return links
   163  }
   164  
   165  // TrackIdComponent interface functions:
   166  
   167  func (p ProofLinkWithState) GetProofState() keybase1.ProofState {
   168  	return p.state
   169  }
   170  
   171  func (p ProofLinkWithState) LastWriterWins() bool {
   172  	return p.link.LastWriterWins()
   173  }
   174  
   175  func (p ProofLinkWithState) ToIDString() string {
   176  	return p.link.ToIDString()
   177  }
   178  
   179  func (p ProofLinkWithState) ToKeyValuePair() (string, string) {
   180  	return p.link.ToKeyValuePair()
   181  }
   182  
   183  func (p ProofLinkWithState) GetProofType() keybase1.ProofType { return p.link.GetProofType() }
   184  
   185  func (r *RemoteProofLinks) toServiceSummary() (ret UserServiceSummary) {
   186  	ret = make(UserServiceSummary, len(r.links))
   187  	activeProofs := r.Active()
   188  	for _, proof := range activeProofs {
   189  		key, val := proof.ToKeyValuePair()
   190  		ret[key] = val
   191  	}
   192  	return ret
   193  }