1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4// 5package engine 6 7import ( 8 "encoding/json" 9 "regexp" 10 11 "github.com/keybase/client/go/libkb" 12 keybase1 "github.com/keybase/client/go/protocol/keybase1" 13) 14 15// SigsList is an engine for the sigs-list command. 16type SigsList struct { 17 SigsListArgs 18 19 user *libkb.User 20 sigs []libkb.TypedChainLink 21 libkb.Contextified 22} 23 24type SigsListArgs struct { 25 Username string 26 Types map[string]bool 27 Filterx string 28 Verbose bool 29 Revoked bool 30} 31 32// NewSigsList creates a SigsList engine. 33func NewSigsList(g *libkb.GlobalContext, args SigsListArgs) *SigsList { 34 return &SigsList{ 35 SigsListArgs: args, 36 Contextified: libkb.NewContextified(g), 37 } 38} 39 40// Name is the unique engine name. 41func (e *SigsList) Name() string { 42 return "SigsList" 43} 44 45// GetPrereqs returns the engine prereqs. 46func (e *SigsList) Prereqs() Prereqs { 47 return Prereqs{} 48} 49 50// RequiredUIs returns the required UIs. 51func (e *SigsList) RequiredUIs() []libkb.UIKind { 52 return []libkb.UIKind{} 53} 54 55// SubConsumers returns the other UI consumers for this engine. 56func (e *SigsList) SubConsumers() []libkb.UIConsumer { 57 return nil 58} 59 60// Run starts the engine. 61func (e *SigsList) Run(m libkb.MetaContext) error { 62 arg := libkb.NewLoadUserArgWithMetaContext(m) 63 if len(e.Username) > 0 { 64 arg = arg.WithName(e.Username) 65 } else { 66 arg = arg.WithSelf(true) 67 } 68 69 var err error 70 e.user, err = libkb.LoadUser(arg) 71 if err != nil { 72 return err 73 } 74 75 e.sigs = e.user.IDTable().Order 76 return e.processSigs() 77} 78 79// Sigs returns the sig list, after processing. 80func (e *SigsList) Sigs() []keybase1.Sig { 81 res := make([]keybase1.Sig, len(e.sigs)) 82 for i, s := range e.sigs { 83 var key string 84 fp := s.GetPGPFingerprint() 85 if fp != nil { 86 key = fp.ToDisplayString(e.Verbose) 87 } 88 res[i] = keybase1.Sig{ 89 Seqno: s.GetSeqno(), 90 SigIDDisplay: s.GetSigID().ToDisplayString(e.Verbose), 91 Type: s.Type(), 92 CTime: keybase1.ToTime(s.GetCTime()), 93 Revoked: s.IsRevoked(), 94 Active: e.isActiveKey(s), 95 Key: key, 96 Body: s.ToDisplayString(), 97 } 98 } 99 return res 100} 101 102// ugh 103type sigexp struct { 104 Seqno keybase1.Seqno `json:"seqno"` 105 SigID string `json:"sig_id"` 106 Type string `json:"type"` 107 CTime int64 `json:"ctime"` 108 Revoked bool `json:"revoked"` 109 Active bool `json:"active"` 110 Key string `json:"key_fingerprint,omitempty"` 111 Body string `json:"statement"` 112} 113 114func (e *SigsList) JSON() (string, error) { 115 exp := make([]sigexp, len(e.sigs)) 116 for i, s := range e.sigs { 117 var key string 118 fp := s.GetPGPFingerprint() 119 if fp != nil { 120 key = fp.ToDisplayString(true /* verbose */) 121 } 122 exp[i] = sigexp{ 123 Seqno: s.GetSeqno(), 124 SigID: s.GetSigID().ToDisplayString(true /* verbose */), 125 Type: s.Type(), 126 CTime: s.GetCTime().Unix(), 127 Revoked: s.IsRevoked(), 128 Active: e.isActiveKey(s), 129 Key: key, 130 Body: s.ToDisplayString(), 131 } 132 } 133 j, err := json.MarshalIndent(exp, "", "\t") 134 if err != nil { 135 return "", err 136 } 137 return string(j), nil 138 139} 140 141func (e *SigsList) processSigs() error { 142 if err := e.skipSigs(); err != nil { 143 return err 144 } 145 if err := e.selectSigs(); err != nil { 146 return err 147 } 148 return e.filterRxx() 149} 150 151func (e *SigsList) skipSigs() error { 152 e.filterSigs(func(l libkb.TypedChainLink) bool { 153 return !e.skipLink(l) 154 }) 155 return nil 156} 157 158func (e *SigsList) selectSigs() error { 159 if e.Types != nil { 160 e.filterSigs(func(l libkb.TypedChainLink) bool { 161 ok, found := e.Types[l.Type()] 162 return ok && found 163 }) 164 } 165 return nil 166} 167 168func (e *SigsList) filterRxx() error { 169 if len(e.Filterx) == 0 { 170 return nil 171 } 172 rxx, err := regexp.Compile(e.Filterx) 173 if err != nil { 174 return err 175 } 176 e.filterSigs(func(l libkb.TypedChainLink) bool { 177 return rxx.MatchString(l.ToDisplayString()) 178 }) 179 return nil 180} 181 182func (e *SigsList) filterSigs(f func(libkb.TypedChainLink) bool) { 183 var sigs []libkb.TypedChainLink 184 for _, link := range e.sigs { 185 if f(link) { 186 sigs = append(sigs, link) 187 } 188 } 189 e.sigs = sigs 190} 191 192func (e *SigsList) isActiveKey(link libkb.TypedChainLink) bool { 193 return link.IsInCurrentFamily(e.user) 194} 195 196func (e *SigsList) skipLink(link libkb.TypedChainLink) bool { 197 return (!e.Revoked && (link.IsRevoked() || link.IsRevocationIsh())) 198} 199