github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/auth/user_keys_api.go (about) 1 package auth 2 3 import ( 4 "time" 5 6 libkb "github.com/keybase/client/go/libkb" 7 logger "github.com/keybase/client/go/logger" 8 keybase1 "github.com/keybase/client/go/protocol/keybase1" 9 context "golang.org/x/net/context" 10 ) 11 12 const ( 13 pollWait = 5 * time.Second 14 ) 15 16 type pubsubMessageInner struct { 17 UID keybase1.UID `json:"uid"` 18 } 19 20 type pubsubMessageOuter struct { 21 SyncStamp int `json:"sync_stamp"` 22 Message pubsubMessageInner `json:"message"` 23 } 24 25 type serverState struct { 26 InstanceID string `json:"instance_id"` 27 LatestSyncStamp int `json:"latest_sync_stamp"` 28 } 29 30 type pubsubResponse struct { 31 Status libkb.AppStatus `json:"status"` 32 ServerState serverState `json:"server_state"` 33 Messages []pubsubMessageOuter `json:"messages"` 34 } 35 36 func (p *pubsubResponse) GetAppStatus() *libkb.AppStatus { 37 return &p.Status 38 } 39 40 var _ UserKeyAPIer = (*userKeyAPI)(nil) 41 42 type userKeysResPublicKeys struct { 43 Sibkeys []keybase1.KID `json:"sibkeys"` 44 Subkeys []keybase1.KID `json:"subkeys"` 45 } 46 47 type userKeyRes struct { 48 Status libkb.AppStatus `json:"status"` 49 Username string `json:"username"` 50 PublicKeys userKeysResPublicKeys `json:"public_keys"` 51 Deleted bool `json:"deleted"` 52 } 53 54 func (k *userKeyRes) GetAppStatus() *libkb.AppStatus { 55 return &k.Status 56 } 57 58 type userKeyAPI struct { 59 log logger.Logger 60 api libkb.API 61 lastSyncPoint int 62 instanceID string 63 } 64 65 func (u *userKeyAPI) GetUser(ctx context.Context, uid keybase1.UID) ( 66 un libkb.NormalizedUsername, sibkeys, subkeys []keybase1.KID, isDeleted bool, err error) { 67 u.log.Debug("+ GetUser") 68 defer func() { 69 u.log.Debug("- GetUser -> %v", err) 70 }() 71 var ukr userKeyRes 72 err = u.api.GetDecodeCtx(ctx, libkb.APIArg{ 73 Endpoint: "user/keys", 74 Args: libkb.HTTPArgs{ 75 "uid": libkb.S{Val: uid.String()}, 76 "load_deleted": libkb.B{Val: true}, 77 }, 78 }, &ukr) 79 if err != nil { 80 return "", nil, nil, false, err 81 } 82 un = libkb.NewNormalizedUsername(ukr.Username) 83 return un, ukr.PublicKeys.Sibkeys, ukr.PublicKeys.Subkeys, ukr.Deleted, nil 84 } 85 86 func (u *userKeyAPI) PollForChanges(ctx context.Context) (uids []keybase1.UID, err error) { 87 defer func() { 88 if err != nil { 89 u.log.Error("- poll -> %v", err) 90 } 91 }() 92 93 var psb pubsubResponse 94 args := libkb.HTTPArgs{ 95 "feed": libkb.S{Val: "user.key_change"}, 96 "last_sync_stamp": libkb.I{Val: u.lastSyncPoint}, 97 "instance_id": libkb.S{Val: u.instanceID}, 98 "wait_for_msec": libkb.I{Val: int(pollWait / time.Millisecond)}, 99 } 100 err = u.api.GetDecodeCtx(ctx, libkb.APIArg{ 101 Endpoint: "pubsub/poll", 102 Args: args, 103 }, &psb) 104 105 // If there was an error (say if the API server was down), then don't busy 106 // loop, wait the pollWait amount of time before exiting. 107 if err != nil { 108 u.log.Debug("Error in poll; waiting for pollWait=%s time", pollWait) 109 select { 110 case <-time.After(pollWait): 111 case <-ctx.Done(): 112 u.log.Debug("Wait short-circuited due to context cancellation") 113 } 114 return uids, err 115 } 116 117 for _, message := range psb.Messages { 118 uids = append(uids, message.Message.UID) 119 } 120 u.lastSyncPoint = psb.ServerState.LatestSyncStamp 121 u.instanceID = psb.ServerState.InstanceID 122 123 return uids, err 124 } 125 126 // NewUserKeyAPIer returns a UserKeyAPIer implementation. 127 func NewUserKeyAPIer(log logger.Logger, api libkb.API) UserKeyAPIer { 128 return &userKeyAPI{log: log, api: api} 129 }