github.com/0chain/gosdk@v1.17.11/zboxapi/sdk.go (about)

     1  package zboxapi
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"net/http"
    10  	"strconv"
    11  	"time"
    12  
    13  	"github.com/0chain/gosdk/zcncore"
    14  
    15  	thrown "github.com/0chain/errors"
    16  	"github.com/0chain/gosdk/core/encryption"
    17  	"github.com/0chain/gosdk/core/logger"
    18  	"github.com/0chain/gosdk/core/resty"
    19  )
    20  
    21  var log logger.Logger
    22  
    23  func GetLogger() *logger.Logger {
    24  	return &log
    25  }
    26  
    27  type Client struct {
    28  	baseUrl          string
    29  	appType          string
    30  	clientID         string
    31  	clientPublicKey  string
    32  	clientPrivateKey string
    33  }
    34  
    35  // NewClient create a zbox api client with wallet info
    36  func NewClient() *Client {
    37  	return &Client{}
    38  }
    39  
    40  // SetRequest set base url and app type of zbox api request
    41  func (c *Client) SetRequest(baseUrl, appType string) {
    42  	c.baseUrl = baseUrl
    43  	c.appType = appType
    44  }
    45  
    46  func (c *Client) SetWallet(clientID, clientPrivateKey, clientPublicKey string) {
    47  	c.clientID = clientID
    48  	c.clientPrivateKey = clientPrivateKey
    49  	c.clientPublicKey = clientPublicKey
    50  }
    51  
    52  func (c *Client) parseResponse(resp *http.Response, respBody []byte, result interface{}) error {
    53  
    54  	log.Info("zboxapi: ", resp.StatusCode, " ", string(respBody))
    55  	if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusCreated {
    56  		if err := json.Unmarshal(respBody, result); err != nil {
    57  			return thrown.Throw(ErrInvalidJsonResponse, string(respBody))
    58  		}
    59  		return nil
    60  	}
    61  
    62  	if len(respBody) == 0 {
    63  		return errors.New(resp.Status)
    64  	}
    65  
    66  	errResp := &ErrorResponse{}
    67  	if err := json.Unmarshal(respBody, errResp); err != nil {
    68  		return thrown.Throw(ErrInvalidJsonResponse, string(respBody))
    69  	}
    70  
    71  	return errors.New(string(errResp.Error))
    72  }
    73  
    74  // GetCsrfToken obtain a fresh csrf token from 0box api server
    75  func (c *Client) GetCsrfToken(ctx context.Context) (string, error) {
    76  	r, err := c.createResty(ctx, "", "", nil)
    77  	if err != nil {
    78  		return "", err
    79  	}
    80  	result := &CsrfTokenResponse{}
    81  	r.DoGet(ctx, c.baseUrl+"/v2/csrftoken").Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
    82  		if err != nil {
    83  			return err
    84  		}
    85  		return c.parseResponse(resp, respBody, result)
    86  	})
    87  
    88  	if err := r.Wait(); len(err) > 0 {
    89  		return "", err[0]
    90  	}
    91  
    92  	return result.Token, nil
    93  }
    94  
    95  func (c *Client) createResty(ctx context.Context, csrfToken, userID string, headers map[string]string) (*resty.Resty, error) {
    96  	h := make(map[string]string)
    97  	h["X-App-Client-ID"] = c.clientID
    98  	h["X-App-Client-Key"] = c.clientPublicKey
    99  	h["X-App-User-ID"] = userID
   100  
   101  	if c.clientPrivateKey != "" {
   102  		data := fmt.Sprintf("%v:%v:%v", c.clientID, userID, c.clientPublicKey)
   103  		hash := encryption.Hash(data)
   104  
   105  		sign, err := zcncore.SignFn(hash)
   106  		if err != nil {
   107  			return nil, err
   108  		}
   109  		h["X-App-Client-Signature"] = sign
   110  	}
   111  
   112  	h["X-CSRF-TOKEN"] = csrfToken
   113  	h["X-App-Timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
   114  
   115  	if _, ok := h["X-App-ID-Token"]; !ok {
   116  		h["X-App-ID-Token"] = "*" //ignore firebase token in jwt requests
   117  	}
   118  
   119  	h["X-App-Type"] = c.appType
   120  
   121  	for k, v := range headers {
   122  		h[k] = v
   123  	}
   124  
   125  	return resty.New(resty.WithHeader(h)), nil
   126  }
   127  
   128  // CreateJwtToken create a jwt token with jwt session id and otp
   129  func (c *Client) CreateJwtToken(ctx context.Context, userID, accessToken string) (string, error) {
   130  	csrfToken, err := c.GetCsrfToken(ctx)
   131  	if err != nil {
   132  		return "", err
   133  	}
   134  	headers := map[string]string{
   135  		"X-App-ID-Token": accessToken,
   136  	}
   137  
   138  	r, err := c.createResty(ctx, csrfToken, userID, headers)
   139  
   140  	if err != nil {
   141  		return "", err
   142  	}
   143  
   144  	result := &JwtTokenResponse{}
   145  	r.DoPost(ctx, nil, c.baseUrl+"/v2/jwt/token").
   146  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   147  			if err != nil {
   148  				return err
   149  			}
   150  
   151  			return c.parseResponse(resp, respBody, result)
   152  		})
   153  
   154  	if errs := r.Wait(); len(errs) > 0 {
   155  		return "", errs[0]
   156  	}
   157  
   158  	return result.Token, nil
   159  }
   160  
   161  // RefreshJwtToken refresh jwt token
   162  func (c *Client) RefreshJwtToken(ctx context.Context, userID string, token string) (string, error) {
   163  	csrfToken, err := c.GetCsrfToken(ctx)
   164  	if err != nil {
   165  		return "", err
   166  	}
   167  	headers := map[string]string{
   168  		"X-JWT-Token": token,
   169  	}
   170  
   171  	r, err := c.createResty(ctx, csrfToken, userID, headers)
   172  
   173  	if err != nil {
   174  		return "", err
   175  	}
   176  
   177  	result := &JwtTokenResponse{}
   178  	r.DoPut(ctx, nil, c.baseUrl+"/v2/jwt/token").
   179  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   180  			if err != nil {
   181  				return err
   182  			}
   183  
   184  			return c.parseResponse(resp, respBody, result)
   185  		})
   186  
   187  	if errs := r.Wait(); len(errs) > 0 {
   188  		return "", errs[0]
   189  	}
   190  
   191  	return result.Token, nil
   192  }
   193  
   194  func (c *Client) GetFreeStorage(ctx context.Context, phoneNumber, token string) (*FreeMarker, error) {
   195  	csrfToken, err := c.GetCsrfToken(ctx)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	headers := map[string]string{
   200  		"X-App-ID-Token": token,
   201  	}
   202  
   203  	r, err := c.createResty(ctx, csrfToken, phoneNumber, headers)
   204  
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	result := &FreeStorageResponse{}
   210  	r.DoGet(ctx, c.baseUrl+"/v2/freestorage").
   211  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   212  			if err != nil {
   213  				return err
   214  			}
   215  
   216  			return c.parseResponse(resp, respBody, result)
   217  		})
   218  
   219  	if errs := r.Wait(); len(errs) > 0 {
   220  		return nil, errs[0]
   221  	}
   222  
   223  	return result.ToMarker()
   224  
   225  }
   226  
   227  func (c *Client) CreateSharedInfo(ctx context.Context, phoneNumber, token string, s SharedInfo) error {
   228  	csrfToken, err := c.GetCsrfToken(ctx)
   229  	if err != nil {
   230  		return err
   231  	}
   232  	headers := map[string]string{
   233  		"X-App-ID-Token": token,
   234  		"Content-Type":   "application/json",
   235  	}
   236  
   237  	r, err := c.createResty(ctx, csrfToken, phoneNumber, headers)
   238  
   239  	if err != nil {
   240  		return err
   241  	}
   242  
   243  	buf, err := json.Marshal(s)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	result := &JsonResult[string]{}
   249  	r.DoPost(ctx, bytes.NewReader(buf), c.baseUrl+"/v2/shareinfo").
   250  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   251  			if err != nil {
   252  				return err
   253  			}
   254  
   255  			return c.parseResponse(resp, respBody, &result)
   256  		})
   257  
   258  	if errs := r.Wait(); len(errs) > 0 {
   259  		return errs[0]
   260  	}
   261  
   262  	return nil
   263  }
   264  
   265  func (c *Client) DeleteSharedInfo(ctx context.Context, phoneNumber, token, authTicket string, lookupHash string) error {
   266  	csrfToken, err := c.GetCsrfToken(ctx)
   267  	if err != nil {
   268  		return err
   269  	}
   270  	headers := map[string]string{
   271  		"X-App-ID-Token": token,
   272  	}
   273  
   274  	r, err := c.createResty(ctx, csrfToken, phoneNumber, headers)
   275  
   276  	if err != nil {
   277  		return err
   278  	}
   279  
   280  	result := &JsonResult[string]{}
   281  	r.DoDelete(ctx, c.baseUrl+"/v2/shareinfo?auth_ticket="+authTicket+"&lookup_hash="+lookupHash).
   282  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   283  			if err != nil {
   284  				return err
   285  			}
   286  
   287  			return c.parseResponse(resp, respBody, &result)
   288  		})
   289  
   290  	if errs := r.Wait(); len(errs) > 0 {
   291  		return errs[0]
   292  	}
   293  
   294  	return nil
   295  }
   296  
   297  func (c *Client) GetSharedByPublic(ctx context.Context, phoneNumber, token string) ([]SharedInfoSent, error) {
   298  	return c.getShared(ctx, phoneNumber, token, false)
   299  }
   300  
   301  func (c *Client) GetSharedByMe(ctx context.Context, phoneNumber, token string) ([]SharedInfoSent, error) {
   302  	return c.getShared(ctx, phoneNumber, token, true)
   303  }
   304  
   305  func (c *Client) getShared(ctx context.Context, phoneNumber, token string, isPrivate bool) ([]SharedInfoSent, error) {
   306  	csrfToken, err := c.GetCsrfToken(ctx)
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  	headers := map[string]string{
   311  		"X-App-ID-Token": token,
   312  	}
   313  
   314  	r, err := c.createResty(ctx, csrfToken, phoneNumber, headers)
   315  
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  
   320  	shareInfoType := "public"
   321  	if isPrivate {
   322  		shareInfoType = "private"
   323  	}
   324  
   325  	result := &JsonResult[SharedInfoSent]{}
   326  	r.DoGet(ctx, c.baseUrl+"/v2/shareinfo/shared?share_info_type="+shareInfoType).
   327  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   328  			if err != nil {
   329  				return err
   330  			}
   331  
   332  			return c.parseResponse(resp, respBody, &result)
   333  		})
   334  
   335  	if errs := r.Wait(); len(errs) > 0 {
   336  		return nil, errs[0]
   337  	}
   338  
   339  	return result.Data, nil
   340  
   341  }
   342  
   343  func (c *Client) GetSharedToMe(ctx context.Context, phoneNumber, token string) ([]SharedInfoReceived, error) {
   344  	csrfToken, err := c.GetCsrfToken(ctx)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  	headers := map[string]string{
   349  		"X-App-ID-Token": token,
   350  	}
   351  
   352  	r, err := c.createResty(ctx, csrfToken, phoneNumber, headers)
   353  
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  
   358  	result := &JsonResult[SharedInfoReceived]{}
   359  	r.DoGet(ctx, c.baseUrl+"/v2/shareinfo/received?share_info_type=private").
   360  		Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   361  			if err != nil {
   362  				return err
   363  			}
   364  
   365  			return c.parseResponse(resp, respBody, &result)
   366  		})
   367  
   368  	if errs := r.Wait(); len(errs) > 0 {
   369  		return nil, errs[0]
   370  	}
   371  
   372  	return result.Data, nil
   373  
   374  }