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 }