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  }