github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/wot_react.go (about) 1 // Copyright 2020 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "errors" 8 "strings" 9 10 "github.com/keybase/client/go/libkb" 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 jsonw "github.com/keybase/go-jsonw" 13 ) 14 15 type WotReactArg struct { 16 Voucher keybase1.UserVersion 17 Proof keybase1.SigID 18 Reaction keybase1.WotReactionType 19 } 20 21 // WotReact is an engine. 22 type WotReact struct { 23 arg *WotReactArg 24 libkb.Contextified 25 } 26 27 // NewWotReact creates a WotReact engine. 28 func NewWotReact(g *libkb.GlobalContext, arg *WotReactArg) *WotReact { 29 return &WotReact{ 30 arg: arg, 31 Contextified: libkb.NewContextified(g), 32 } 33 } 34 35 // Name is the unique engine name. 36 func (e *WotReact) Name() string { 37 return "WotReact" 38 } 39 40 // GetPrereqs returns the engine prereqs. 41 func (e *WotReact) Prereqs() Prereqs { 42 return Prereqs{Device: true} 43 } 44 45 // RequiredUIs returns the required UIs. 46 func (e *WotReact) RequiredUIs() []libkb.UIKind { 47 return []libkb.UIKind{} 48 } 49 50 // SubConsumers returns the other UI consumers for this engine. 51 func (e *WotReact) SubConsumers() []libkb.UIConsumer { 52 return nil 53 } 54 55 // Run starts the engine. 56 func (e *WotReact) Run(mctx libkb.MetaContext) error { 57 luArg := libkb.NewLoadUserArgWithMetaContext(mctx).WithUID(e.arg.Voucher.Uid) 58 them, err := libkb.LoadUser(luArg) 59 if err != nil { 60 return err 61 } 62 if them.GetCurrentEldestSeqno() != e.arg.Voucher.EldestSeqno { 63 return errors.New("voucher has reset, make sure you still know them") 64 } 65 66 statement := jsonw.NewDictionary() 67 if err := statement.SetKey("sig_id", jsonw.NewString(string(e.arg.Proof))); err != nil { 68 return err 69 } 70 reactionType := strings.ToLower(keybase1.WotReactionTypeRevMap[e.arg.Reaction]) 71 if err := statement.SetKey("reaction", jsonw.NewString(reactionType)); err != nil { 72 return err 73 } 74 expansions, sum, err := libkb.EmbedExpansionObj(statement) 75 if err != nil { 76 return err 77 } 78 79 signingKey, err := mctx.G().ActiveDevice.SigningKey() 80 if err != nil { 81 return err 82 } 83 sigVersion := libkb.KeybaseSignatureV2 84 var inner []byte 85 var sig string 86 87 // ForcePoll is required. 88 err = mctx.G().GetFullSelfer().WithSelfForcePoll(mctx.Ctx(), func(me *libkb.User) error { 89 if me.GetUID() == e.arg.Voucher.Uid { 90 return libkb.InvalidArgumentError{Msg: "can't react to a vouch from yourself"} 91 } 92 proof, err := me.WotReactProof(mctx, signingKey, sigVersion, sum) 93 if err != nil { 94 return err 95 } 96 inner, err = proof.J.Marshal() 97 if err != nil { 98 return err 99 } 100 101 sig, _, _, err = libkb.MakeSig( 102 mctx, 103 signingKey, 104 libkb.LinkTypeWotReact, 105 inner, 106 libkb.SigHasRevokes(false), 107 keybase1.SeqType_PUBLIC, 108 libkb.SigIgnoreIfUnsupported(true), 109 me, 110 sigVersion, 111 ) 112 113 return err 114 }) 115 116 if err != nil { 117 return err 118 } 119 120 item := libkb.SigMultiItem{ 121 Sig: sig, 122 SigningKID: signingKey.GetKID(), 123 Type: string(libkb.LinkTypeWotReact), 124 SeqType: keybase1.SeqType_PUBLIC, 125 SigInner: string(inner), 126 Version: sigVersion, 127 Expansions: expansions, 128 } 129 130 payload := make(libkb.JSONPayload) 131 payload["sigs"] = []interface{}{item} 132 133 if _, err := e.G().API.PostJSON(mctx, libkb.APIArg{ 134 Endpoint: "sig/multi", 135 SessionType: libkb.APISessionTypeREQUIRED, 136 JSONPayload: payload, 137 }); err != nil { 138 return err 139 } 140 141 voucheeUsername := mctx.ActiveDevice().Username(mctx).String() 142 mctx.G().NotifyRouter.HandleWebOfTrustChanged(voucheeUsername) 143 return libkb.DismissWotNotifications(mctx, them.GetName(), voucheeUsername) 144 }