github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/delegatekeyaggregator.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 "errors" 8 "time" 9 10 "github.com/keybase/client/go/protocol/keybase1" 11 ) 12 13 // DelegatorAggregator manages delegating multiple keys in one post to the 14 // server When run produces a map which goes into the 'key/multi' 'sigs' list. 15 type AggSigProducer func() (JSONPayload, keybase1.Seqno, LinkID, error) 16 17 // Run posts an array of delegations to the server. Keeping this simple as we 18 // don't need any state (yet) `extra` is optional and adds an extra sig, 19 // produced by something other than a Delegator, after the others. 20 func DelegatorAggregator(m MetaContext, ds []Delegator, extra AggSigProducer, 21 pukBoxes []keybase1.PerUserKeyBox, pukPrev *PerUserKeyPrev, userEKReboxArg *keybase1.UserEkReboxArg) (err error) { 22 if len(ds) == 0 { 23 return errors.New("Empty delegators to aggregator") 24 } 25 26 // Store all the args to build a single big json later 27 var args []JSONPayload 28 var uid keybase1.UID 29 var lastSeqno keybase1.Seqno 30 var lastLinkID LinkID 31 32 for i := range ds { 33 // Mutate the original and not a copy from range 34 var d = &ds[i] 35 36 d.Aggregated = true 37 if err := d.Run(m); err != nil { 38 return err 39 } 40 41 flatArgs := d.postArg.flattenHTTPArgs(d.postArg.getHTTPArgs()) 42 args = append(args, convertStringMapToJSONPayload(flatArgs)) 43 if uid.IsNil() && d.Me != nil { 44 uid = d.Me.GetUID() 45 } 46 lastSeqno = d.proof.Seqno 47 lastLinkID = d.linkID 48 } 49 50 if extra != nil { 51 x, seqno, linkID, err := extra() 52 if err != nil { 53 return err 54 } 55 args = append(args, x) 56 lastSeqno = seqno 57 lastLinkID = linkID 58 } 59 60 payload := make(JSONPayload) 61 payload["sigs"] = args 62 63 if len(pukBoxes) > 0 { 64 AddPerUserKeyServerArg(payload, pukBoxes[0].Generation, pukBoxes, pukPrev) 65 } else if pukPrev != nil { 66 return errors.New("cannot delegate per-user-key with prev but no boxes") 67 } 68 AddUserEKReBoxServerArg(payload, userEKReboxArg) 69 70 // Adopt most parameters from the first item 71 var apiArgBase = ds[0] 72 var apiArg = apiArgBase.postArg 73 apiArg.Args = nil 74 apiArg.uArgs = nil 75 apiArg.Endpoint = "key/multi" 76 apiArg.JSONPayload = payload 77 // It's bad to fail provisioning especially after signup. 78 apiArg.InitialTimeout = 5 * time.Minute 79 apiArg.RetryCount = 10 80 81 _, err = m.G().API.PostJSON(m, apiArg) 82 if err != nil { 83 return err 84 } 85 return MerkleCheckPostedUserSig(m, uid, lastSeqno, lastLinkID) 86 } 87 88 // Make the "per_user_key" section of an API arg. 89 // Requires one or more `pukBoxes` 90 // `pukPrev` is optional. 91 // Modifies `serverArg`. 92 func AddPerUserKeyServerArg(serverArg JSONPayload, generation keybase1.PerUserKeyGeneration, 93 pukBoxes []keybase1.PerUserKeyBox, pukPrev *PerUserKeyPrev) { 94 section := make(JSONPayload) 95 section["boxes"] = pukBoxes 96 section["generation"] = generation 97 if pukPrev != nil { 98 section["prev"] = *pukPrev 99 } 100 serverArg["per_user_key"] = section 101 } 102 103 // Make the "user_ek_rebox" and "device_eks" section of an API arg. Modifies 104 // `serverArg` unless arg is nil. 105 func AddUserEKReBoxServerArg(serverArg JSONPayload, arg *keybase1.UserEkReboxArg) { 106 if arg == nil { 107 return 108 } 109 serverArg["device_eks"] = map[string]string{string(arg.DeviceID): arg.DeviceEkStatementSig} 110 serverArg["user_ek_rebox"] = arg.UserEkBoxMetadata 111 } 112 113 func convertStringMapToJSONPayload(in map[string]string) JSONPayload { 114 out := make(JSONPayload) 115 for k, v := range in { 116 out[k] = v 117 } 118 return out 119 }