github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/post.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 "fmt" 8 "runtime/debug" 9 10 keybase1 "github.com/keybase/client/go/protocol/keybase1" 11 jsonw "github.com/keybase/go-jsonw" 12 ) 13 14 type PostProofRes struct { 15 Text string 16 ID string 17 Metadata *jsonw.Wrapper 18 } 19 20 type PostProofArg struct { 21 UID keybase1.UID 22 Seqno keybase1.Seqno 23 Sig string 24 SigInner []byte 25 RemoteServiceType string 26 SigID keybase1.SigID 27 LinkID LinkID 28 RemoteUsername string 29 ProofType string 30 Supersede bool 31 RemoteKey string 32 SigningKey GenericKey 33 } 34 35 func PostProof(m MetaContext, arg PostProofArg) (*PostProofRes, error) { 36 hargs := HTTPArgs{ 37 "sig_id_base": S{arg.SigID.StripSuffix().String()}, 38 "sig_id_short": S{arg.SigID.ToShortID()}, 39 "sig": S{arg.Sig}, 40 "is_remote_proof": B{true}, 41 "supersede": B{arg.Supersede}, 42 "signing_kid": S{arg.SigningKey.GetKID().String()}, 43 "type": S{arg.ProofType}, 44 } 45 if len(arg.SigInner) > 0 { 46 hargs["sig_inner"] = S{string(arg.SigInner)} 47 } 48 49 if arg.ProofType == GenericSocialWebServiceBinding { 50 hargs["remote_service"] = S{arg.RemoteServiceType} 51 } 52 53 hargs.Add(arg.RemoteKey, S{arg.RemoteUsername}) 54 55 apiRes, err := m.G().API.Post(m, APIArg{ 56 Endpoint: "sig/post", 57 SessionType: APISessionTypeREQUIRED, 58 Args: hargs, 59 }) 60 if err != nil { 61 return nil, err 62 } 63 64 err = MerkleCheckPostedUserSig(m, arg.UID, arg.Seqno, arg.LinkID) 65 if err != nil { 66 return nil, err 67 } 68 69 var res PostProofRes 70 res.Text, err = apiRes.Body.AtKey("proof_text").GetString() 71 if err != nil { 72 return nil, err 73 } 74 res.ID, err = apiRes.Body.AtKey("proof_id").GetString() 75 if err != nil { 76 return nil, err 77 } 78 res.Metadata = apiRes.Body.AtKey("proof_metadata") 79 return &res, nil 80 } 81 82 type PostAuthProofArg struct { 83 uid keybase1.UID 84 sig string 85 key GenericKey 86 } 87 88 type PostAuthProofRes struct { 89 SessionID string `json:"session"` 90 AuthID string `json:"auth_id"` 91 CSRFToken string `json:"csrf_token"` 92 UIDHex string `json:"uid"` 93 Username string `json:"username"` 94 PPGen int `json:"passphrase_generation"` 95 } 96 97 func PostAuthProof(m MetaContext, arg PostAuthProofArg) (*PostAuthProofRes, error) { 98 hargs := HTTPArgs{ 99 "uid": UIDArg(arg.uid), 100 "sig": S{arg.sig}, 101 "signing_kid": S{arg.key.GetKID().String()}, 102 } 103 res, err := m.G().API.Post(m, APIArg{ 104 Endpoint: "sig/post_auth", 105 SessionType: APISessionTypeNONE, 106 Args: hargs, 107 }) 108 if err != nil { 109 return nil, err 110 } 111 var ret *PostAuthProofRes 112 var tmp PostAuthProofRes 113 if err = res.Body.UnmarshalAgain(&tmp); err == nil { 114 ret = &tmp 115 } 116 return ret, err 117 } 118 119 type InviteRequestArg struct { 120 Email string 121 Fullname string 122 Notes string 123 } 124 125 func PostInviteRequest(m MetaContext, arg InviteRequestArg) (err error) { 126 _, err = m.G().API.Post(m, APIArg{ 127 Endpoint: "invitation_request", 128 Args: HTTPArgs{ 129 "email": S{arg.Email}, 130 "full_name": S{arg.Fullname}, 131 "notes": S{arg.Notes}, 132 }, 133 }) 134 return err 135 } 136 137 func DeletePrimary(m MetaContext) (err error) { 138 _, err = m.G().API.Post(m, APIArg{ 139 Endpoint: "key/revoke", 140 SessionType: APISessionTypeREQUIRED, 141 Args: HTTPArgs{ 142 "revoke_primary": I{1}, 143 "revocation_type": I{RevSimpleDelete}, 144 }, 145 }) 146 return 147 } 148 149 func CheckPosted(mctx MetaContext, sigID keybase1.SigID) (found bool, status keybase1.ProofStatus, state keybase1.ProofState, err error) { 150 defer mctx.Trace(fmt.Sprintf("CheckPosted(%v)", sigID), &err)() 151 found, status, state, err = checkPostedAPICall(mctx, sigID) 152 if err != nil { 153 return found, status, state, err 154 } 155 // Bust proof cache if it disagrees about success. 156 err = checkPostedMaybeBustProofCache(mctx, sigID, found, status, state) 157 if err != nil { 158 mctx.Debug("| CheckPosted error maybe busting proof cache: %v", err) 159 } 160 return found, status, state, nil 161 } 162 163 func checkPostedAPICall(mctx MetaContext, sigID keybase1.SigID) (found bool, status keybase1.ProofStatus, state keybase1.ProofState, err error) { 164 res, e2 := mctx.G().API.Post(mctx, APIArg{ 165 Endpoint: "sig/posted", 166 SessionType: APISessionTypeREQUIRED, 167 Args: HTTPArgs{ 168 "sig_id": S{sigID.String()}, 169 }, 170 }) 171 if e2 != nil { 172 err = e2 173 return 174 } 175 176 var ( 177 rfound bool 178 rstatus int 179 rstate int 180 rerr error 181 ) 182 res.Body.AtKey("proof_ok").GetBoolVoid(&rfound, &rerr) 183 res.Body.AtPath("proof_res.status").GetIntVoid(&rstatus, &rerr) 184 res.Body.AtPath("proof_res.state").GetIntVoid(&rstate, &rerr) 185 return rfound, keybase1.ProofStatus(rstatus), keybase1.ProofState(rstate), rerr 186 } 187 188 func checkPostedMaybeBustProofCache(mctx MetaContext, sigID keybase1.SigID, found bool, status keybase1.ProofStatus, state keybase1.ProofState) error { 189 pvlSource := mctx.G().GetPvlSource() 190 if pvlSource == nil { 191 return fmt.Errorf("no pvl source") 192 } 193 pvlU, err := pvlSource.GetLatestEntry(mctx) 194 if err != nil { 195 return fmt.Errorf("error getting pvl: %v", err) 196 } 197 checkResult := mctx.G().ProofCache.Get(sigID, pvlU.Hash) 198 if checkResult == nil { 199 return nil 200 } 201 serverOk := found && state == keybase1.ProofState_OK 202 cacheOk := checkResult.Status == nil || checkResult.Status.GetProofStatus() == keybase1.ProofStatus_OK 203 if serverOk != cacheOk { 204 mctx.Debug("CheckPosted busting %v", sigID) 205 return mctx.G().ProofCache.Delete(sigID) 206 } 207 return nil 208 } 209 210 func PostDeviceLKS(m MetaContext, deviceID keybase1.DeviceID, deviceType keybase1.DeviceTypeV2, serverHalf LKSecServerHalf, 211 ppGen PassphraseGeneration, 212 clientHalfRecovery string, clientHalfRecoveryKID keybase1.KID) error { 213 m.Debug("| PostDeviceLKS: %s", deviceID) 214 if serverHalf.IsNil() { 215 return fmt.Errorf("PostDeviceLKS: called with empty serverHalf") 216 } 217 if ppGen < 1 { 218 m.Warning("PostDeviceLKS: ppGen < 1 (%d)", ppGen) 219 debug.PrintStack() 220 } 221 arg := APIArg{ 222 Endpoint: "device/update", 223 SessionType: APISessionTypeREQUIRED, 224 Args: HTTPArgs{ 225 "device_id": S{Val: deviceID.String()}, 226 "type": S{Val: deviceType.String()}, 227 "lks_server_half": S{Val: serverHalf.EncodeToHex()}, 228 "ppgen": I{Val: int(ppGen)}, 229 "lks_client_half": S{Val: clientHalfRecovery}, 230 "kid": S{Val: clientHalfRecoveryKID.String()}, 231 "platform": S{Val: GetPlatformString()}, 232 }, 233 RetryCount: 10, 234 } 235 _, err := m.G().API.Post(m, arg) 236 if err != nil { 237 m.Info("device/update(%+v) failed: %s", arg.Args, err) 238 } 239 return err 240 } 241 242 func CheckInvitationCode(m MetaContext, code string) error { 243 arg := APIArg{ 244 Endpoint: "invitation/check", 245 SessionType: APISessionTypeNONE, 246 Args: HTTPArgs{ 247 "invitation_id": S{Val: code}, 248 }, 249 } 250 _, err := m.G().API.Get(m, arg) 251 return err 252 } 253 254 func GetInvitationCode(m MetaContext) (string, error) { 255 arg := APIArg{ 256 Endpoint: "invitation_bypass_request", 257 SessionType: APISessionTypeNONE, 258 } 259 res, err := m.G().API.Get(m, arg) 260 var invitationID string 261 if err == nil { 262 invitationID, err = res.Body.AtKey("invitation_id").GetString() 263 } 264 return invitationID, err 265 }