github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/service/apiserver.go (about)

     1  // Copyright 2016 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package service
     5  
     6  import (
     7  	"encoding/json"
     8  	"io"
     9  
    10  	"github.com/keybase/client/go/libkb"
    11  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    12  	"github.com/keybase/go-framed-msgpack-rpc/rpc"
    13  	jsonw "github.com/keybase/go-jsonw"
    14  	"golang.org/x/net/context"
    15  )
    16  
    17  type APIServerHandler struct {
    18  	*BaseHandler
    19  	libkb.Contextified
    20  }
    21  
    22  func NewAPIServerHandler(xp rpc.Transporter, g *libkb.GlobalContext) *APIServerHandler {
    23  	return &APIServerHandler{
    24  		BaseHandler:  NewBaseHandler(g, xp),
    25  		Contextified: libkb.NewContextified(g),
    26  	}
    27  }
    28  
    29  func (a *APIServerHandler) Get(ctx context.Context, arg keybase1.GetArg) (keybase1.APIRes, error) {
    30  	mctx := libkb.NewMetaContext(ctx, a.G())
    31  	return a.doGet(mctx, arg, false)
    32  }
    33  
    34  func (a *APIServerHandler) GetWithSession(ctx context.Context, arg keybase1.GetWithSessionArg) (keybase1.APIRes, error) {
    35  	mctx := libkb.NewMetaContext(ctx, a.G())
    36  	return a.doGet(mctx, arg, true)
    37  }
    38  
    39  func (a *APIServerHandler) Post(ctx context.Context, arg keybase1.PostArg) (keybase1.APIRes, error) {
    40  	mctx := libkb.NewMetaContext(ctx, a.G())
    41  	return a.doPost(mctx, arg)
    42  }
    43  
    44  func (a *APIServerHandler) PostJSON(ctx context.Context, arg keybase1.PostJSONArg) (keybase1.APIRes, error) {
    45  	mctx := libkb.NewMetaContext(ctx, a.G())
    46  	return a.doPostJSON(mctx, arg)
    47  }
    48  
    49  func (a *APIServerHandler) Delete(ctx context.Context, arg keybase1.DeleteArg) (keybase1.APIRes, error) {
    50  	mctx := libkb.NewMetaContext(ctx, a.G())
    51  	return a.doDelete(mctx, arg)
    52  }
    53  
    54  type GenericArg interface {
    55  	GetEndpoint() string
    56  	GetHTTPArgs() []keybase1.StringKVPair
    57  	GetHttpStatuses() []int
    58  	GetAppStatusCodes() []int
    59  }
    60  
    61  func (a *APIServerHandler) setupArg(arg GenericArg) libkb.APIArg {
    62  	// Form http arg dict
    63  	kbargs := make(libkb.HTTPArgs)
    64  	for _, harg := range arg.GetHTTPArgs() {
    65  		kbargs[harg.Key] = libkb.S{Val: harg.Value}
    66  	}
    67  
    68  	// Acceptable http status list
    69  	s := arg.GetHttpStatuses()
    70  	httpStatuses := make([]int, len(s))
    71  	copy(httpStatuses, s)
    72  
    73  	// Acceptable app status code list
    74  	c := arg.GetAppStatusCodes()
    75  	appStatusCodes := make([]int, len(c))
    76  	copy(appStatusCodes, c)
    77  
    78  	// Do the API call
    79  	kbarg := libkb.APIArg{
    80  		Endpoint:       arg.GetEndpoint(),
    81  		SessionType:    libkb.APISessionTypeREQUIRED,
    82  		Args:           kbargs,
    83  		HTTPStatus:     httpStatuses,
    84  		AppStatusCodes: appStatusCodes,
    85  	}
    86  
    87  	return kbarg
    88  }
    89  
    90  func (a *APIServerHandler) doGet(mctx libkb.MetaContext, arg GenericArg, sessionRequired bool) (res keybase1.APIRes, err error) {
    91  	defer mctx.Trace("APIServerHandler::Get", &err)()
    92  	// turn off session requirement if not needed
    93  	kbarg := a.setupArg(arg)
    94  	if !sessionRequired {
    95  		kbarg.SessionType = libkb.APISessionTypeNONE
    96  	}
    97  	if getWithSessionArg, ok := arg.(keybase1.GetWithSessionArg); ok && getWithSessionArg.UseText != nil && *getWithSessionArg.UseText {
    98  		kbarg.UseText = true
    99  		resp, finisher, err := mctx.G().API.GetResp(mctx, kbarg)
   100  		defer finisher()
   101  		if err != nil {
   102  			return res, err
   103  		}
   104  		body, err := io.ReadAll(resp.Body)
   105  		if err != nil {
   106  			return res, err
   107  		}
   108  		return keybase1.APIRes{
   109  			Body:       string(body),
   110  			HttpStatus: resp.StatusCode,
   111  		}, nil
   112  	}
   113  	var ires *libkb.APIRes
   114  	ires, err = mctx.G().API.Get(mctx, kbarg)
   115  	if err != nil {
   116  		return res, err
   117  	}
   118  	return a.convertRes(ires), nil
   119  }
   120  
   121  func (a *APIServerHandler) doPost(mctx libkb.MetaContext, arg keybase1.PostArg) (res keybase1.APIRes, err error) {
   122  	defer mctx.Trace("APIServerHandler::Post", &err)()
   123  	var ires *libkb.APIRes
   124  	ires, err = mctx.G().API.Post(mctx, a.setupArg(arg))
   125  	if err != nil {
   126  		return res, err
   127  	}
   128  	return a.convertRes(ires), nil
   129  }
   130  
   131  func (a *APIServerHandler) doPostJSON(mctx libkb.MetaContext, rawarg keybase1.PostJSONArg) (res keybase1.APIRes, err error) {
   132  	defer mctx.Trace("APIServerHandler::PostJSON", &err)()
   133  	var ires *libkb.APIRes
   134  	arg := a.setupArg(rawarg)
   135  	jsonPayload := make(libkb.JSONPayload)
   136  	for _, kvpair := range rawarg.JSONPayload {
   137  		var value interface{}
   138  		err = jsonw.EnsureMaxDepthBytesDefault([]byte(kvpair.Value))
   139  		if err != nil {
   140  			return keybase1.APIRes{}, err
   141  		}
   142  		err := json.Unmarshal([]byte(kvpair.Value), &value)
   143  		if err != nil {
   144  			return keybase1.APIRes{}, err
   145  		}
   146  		jsonPayload[kvpair.Key] = value
   147  	}
   148  	arg.JSONPayload = jsonPayload
   149  
   150  	ires, err = mctx.G().API.PostJSON(mctx, arg)
   151  	if err != nil {
   152  		return keybase1.APIRes{}, err
   153  	}
   154  
   155  	return a.convertRes(ires), nil
   156  }
   157  
   158  func (a *APIServerHandler) doDelete(mctx libkb.MetaContext, arg keybase1.DeleteArg) (res keybase1.APIRes, err error) {
   159  	a.G().Trace("APIServerHandler::Delete", &err)()
   160  	var ires *libkb.APIRes
   161  	ires, err = a.G().API.Delete(mctx, a.setupArg(arg))
   162  	if err != nil {
   163  		return res, err
   164  	}
   165  	return a.convertRes(ires), nil
   166  }
   167  
   168  func (a *APIServerHandler) convertRes(res *libkb.APIRes) keybase1.APIRes {
   169  	// Translate the result
   170  	var ares keybase1.APIRes
   171  	mstatus, err := res.Status.Marshal()
   172  	if err == nil {
   173  		ares.Status = string(mstatus)
   174  	}
   175  	mbody, err := res.Body.Marshal()
   176  	if err == nil {
   177  		ares.Body = string(mbody)
   178  	}
   179  	ares.HttpStatus = res.HTTPStatus
   180  
   181  	appStatus := jsonw.NewWrapper(res.AppStatus)
   182  	mappstatus, err := appStatus.Marshal()
   183  	if err == nil {
   184  		ares.AppStatus = string(mappstatus)
   185  	}
   186  
   187  	return ares
   188  }