github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/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  }