github.com/0chain/gosdk@v1.17.11/zcncore/zauth.go (about)

     1  package zcncore
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  
    10  	"github.com/0chain/gosdk/core/sys"
    11  	"github.com/0chain/gosdk/zboxcore/client"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  // SplitWallet represents wallet info for split wallet
    16  // The client id and client key are the same as the primary wallet client id and client key
    17  type SplitWallet struct {
    18  	ClientID      string `json:"client_id"`
    19  	ClientKey     string `json:"client_key"`
    20  	PublicKey     string `json:"public_key"`
    21  	PrivateKey    string `json:"private_key"`
    22  	PeerPublicKey string `json:"peer_public_key"`
    23  	IsRevoked     bool   `json:"is_revoked"`
    24  	ExpiredAt     int64  `json:"expired_at"`
    25  }
    26  
    27  // CallZauthSetup calls the zauth setup endpoint
    28  func CallZauthSetup(serverAddr string, token string, splitWallet SplitWallet) error {
    29  	// Add your code here
    30  	endpoint := serverAddr + "/setup"
    31  	wData, err := json.Marshal(splitWallet)
    32  	if err != nil {
    33  		return errors.Wrap(err, "failed to marshal split wallet")
    34  	}
    35  
    36  	req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(wData))
    37  	if err != nil {
    38  		return errors.Wrap(err, "failed to create HTTP request")
    39  	}
    40  
    41  	req.Header.Set("Content-Type", "application/json")
    42  	req.Header.Set("X-Jwt-Token", token)
    43  
    44  	client := &http.Client{}
    45  	resp, err := client.Do(req)
    46  	if err != nil {
    47  		return errors.Wrap(err, "failed to send HTTP request")
    48  	}
    49  	defer resp.Body.Close()
    50  
    51  	if resp.StatusCode != http.StatusOK {
    52  		errMsg, _ := io.ReadAll(resp.Body)
    53  		if len(errMsg) > 0 {
    54  			return errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
    55  		}
    56  
    57  		return errors.Errorf("code: %d", resp.StatusCode)
    58  	}
    59  
    60  	var rsp struct {
    61  		Result string `json:"result"`
    62  	}
    63  	if err := json.NewDecoder(resp.Body).Decode(&rsp); err != nil {
    64  		return errors.Wrap(err, "failed to decode response body")
    65  	}
    66  
    67  	if rsp.Result != "success" {
    68  		return errors.New("failed to setup zauth server")
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  func CallZauthRevoke(serverAddr, token, clientID, publicKey string) error {
    75  	endpoint := serverAddr + "/revoke/" + clientID
    76  	endpoint += "?peer_public_key=" + publicKey
    77  	req, err := http.NewRequest("POST", endpoint, nil)
    78  	if err != nil {
    79  		return errors.Wrap(err, "failed to create HTTP request")
    80  	}
    81  
    82  	req.Header.Set("Content-Type", "application/json")
    83  	req.Header.Set("X-Jwt-Token", token)
    84  
    85  	client := &http.Client{}
    86  	resp, err := client.Do(req)
    87  	if err != nil {
    88  		return errors.Wrap(err, "failed to send HTTP request")
    89  	}
    90  	defer resp.Body.Close()
    91  
    92  	if resp.StatusCode != http.StatusOK {
    93  		errMsg, _ := io.ReadAll(resp.Body)
    94  		if len(errMsg) > 0 {
    95  			return errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
    96  		}
    97  
    98  		return errors.Errorf("code: %d", resp.StatusCode)
    99  	}
   100  
   101  	var rsp struct {
   102  		Result string `json:"result"`
   103  	}
   104  	if err := json.NewDecoder(resp.Body).Decode(&rsp); err != nil {
   105  		return errors.Wrap(err, "failed to decode response body")
   106  	}
   107  
   108  	if rsp.Result != "success" {
   109  		return errors.New("failed to setup zauth server")
   110  	}
   111  
   112  	return nil
   113  }
   114  
   115  func CallZauthDelete(serverAddr, token, clientID string) error {
   116  	endpoint := serverAddr + "/delete/" + clientID
   117  	req, err := http.NewRequest("POST", endpoint, nil)
   118  	if err != nil {
   119  		return errors.Wrap(err, "failed to create HTTP request")
   120  	}
   121  
   122  	req.Header.Set("Content-Type", "application/json")
   123  	req.Header.Set("X-Jwt-Token", token)
   124  
   125  	client := &http.Client{}
   126  	resp, err := client.Do(req)
   127  	if err != nil {
   128  		return errors.Wrap(err, "failed to send HTTP request")
   129  	}
   130  
   131  	defer resp.Body.Close()
   132  	if resp.StatusCode != http.StatusOK {
   133  		errMsg, _ := io.ReadAll(resp.Body)
   134  		if len(errMsg) > 0 {
   135  			return errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   136  		}
   137  
   138  		return errors.Errorf("code: %d", resp.StatusCode)
   139  	}
   140  
   141  	var rsp struct {
   142  		Result string `json:"result"`
   143  	}
   144  	if err := json.NewDecoder(resp.Body).Decode(&rsp); err != nil {
   145  		return errors.Wrap(err, "failed to decode response body")
   146  	}
   147  
   148  	if rsp.Result != "success" {
   149  		return errors.New("failed to setup zauth server")
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func CallZvaultNewWalletString(serverAddr, token, clientID string) (string, error) {
   156  	// Add your code here
   157  	endpoint := serverAddr + "/generate"
   158  	if clientID != "" {
   159  		endpoint = endpoint + "/" + clientID
   160  	}
   161  
   162  	req, err := http.NewRequest("POST", endpoint, nil)
   163  	if err != nil {
   164  		return "", errors.Wrap(err, "failed to create HTTP request")
   165  	}
   166  
   167  	fmt.Println("new wallet endpoint:", endpoint)
   168  	fmt.Println("new wallet: serverAddr:", serverAddr)
   169  	fmt.Println("new wallet: clientID:", clientID)
   170  
   171  	req.Header.Set("Content-Type", "application/json")
   172  	req.Header.Set("X-Jwt-Token", token)
   173  
   174  	client := &http.Client{}
   175  	resp, err := client.Do(req)
   176  	if err != nil {
   177  		return "", errors.Wrap(err, "failed to send HTTP request")
   178  	}
   179  	defer resp.Body.Close()
   180  
   181  	if resp.StatusCode != http.StatusOK {
   182  		errMsg, _ := io.ReadAll(resp.Body)
   183  		if len(errMsg) > 0 {
   184  			return "", errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   185  		}
   186  
   187  		return "", errors.Errorf("code: %d", resp.StatusCode)
   188  	}
   189  
   190  	d, err := io.ReadAll(resp.Body)
   191  	if err != nil {
   192  		return "", errors.Wrap(err, "failed to read response body")
   193  	}
   194  
   195  	return string(d), nil
   196  }
   197  
   198  func CallZvaultStoreKeyString(serverAddr, token, privateKey string) (string, error) {
   199  	// Add your code here
   200  	endpoint := serverAddr + "/store"
   201  
   202  	reqData := struct {
   203  		PrivateKey string `json:"private_key"`
   204  	}{
   205  		PrivateKey: privateKey,
   206  	}
   207  
   208  	var buff bytes.Buffer
   209  
   210  	encoder := json.NewEncoder(&buff)
   211  
   212  	err := encoder.Encode(reqData)
   213  	if err != nil {
   214  		return "", errors.Wrap(err, "failed to create HTTP request")
   215  	}
   216  
   217  	var req *http.Request
   218  
   219  	req, err = http.NewRequest("POST", endpoint, &buff)
   220  	if err != nil {
   221  		return "", errors.Wrap(err, "failed to create HTTP request")
   222  	}
   223  
   224  	fmt.Println("call zvault /store:", endpoint)
   225  	req.Header.Set("Content-Type", "application/json")
   226  	req.Header.Set("X-Jwt-Token", token)
   227  
   228  	fmt.Println(req)
   229  
   230  	client := &http.Client{}
   231  	resp, err := client.Do(req)
   232  	if err != nil {
   233  		fmt.Println(err.Error())
   234  
   235  		return "", errors.Wrap(err, "failed to send HTTP request")
   236  	}
   237  	defer resp.Body.Close()
   238  
   239  	if resp.StatusCode != http.StatusOK {
   240  		errMsg, _ := io.ReadAll(resp.Body)
   241  		if len(errMsg) > 0 {
   242  			return "", errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   243  		}
   244  
   245  		return "", errors.Errorf("code: %d", resp.StatusCode)
   246  	}
   247  
   248  	d, err := io.ReadAll(resp.Body)
   249  	if err != nil {
   250  		return "", errors.Wrap(err, "failed to read response body")
   251  	}
   252  
   253  	return string(d), nil
   254  }
   255  
   256  func CallZvaultRetrieveKeys(serverAddr, token, clientID string) (string, error) {
   257  	// Add your code here
   258  	endpoint := fmt.Sprintf("%s/keys/%s", serverAddr, clientID)
   259  	req, err := http.NewRequest("GET", endpoint, nil)
   260  	if err != nil {
   261  		return "", errors.Wrap(err, "failed to create HTTP request")
   262  	}
   263  
   264  	fmt.Println("call zvault /keys:", endpoint)
   265  	req.Header.Set("Content-Type", "application/json")
   266  	req.Header.Set("X-Jwt-Token", token)
   267  
   268  	client := &http.Client{}
   269  	resp, err := client.Do(req)
   270  	if err != nil {
   271  		return "", errors.Wrap(err, "failed to send HTTP request")
   272  	}
   273  	defer resp.Body.Close()
   274  
   275  	if resp.StatusCode != http.StatusOK {
   276  		errMsg, _ := io.ReadAll(resp.Body)
   277  		return "", fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   278  	}
   279  
   280  	d, err := io.ReadAll(resp.Body)
   281  	if err != nil {
   282  		return "", errors.Wrap(err, "failed to read response body")
   283  	}
   284  
   285  	return string(d), nil
   286  }
   287  
   288  func CallZvaultDeletePrimaryKey(serverAddr, token, clientID string) error {
   289  	// Add your code here
   290  	endpoint := serverAddr + "/delete/" + clientID
   291  	req, err := http.NewRequest("POST", endpoint, nil)
   292  	if err != nil {
   293  		return errors.Wrap(err, "failed to create HTTP request")
   294  	}
   295  
   296  	fmt.Println("call zvault /delete:", endpoint)
   297  	req.Header.Set("Content-Type", "application/json")
   298  	req.Header.Set("X-Jwt-Token", token)
   299  
   300  	client := &http.Client{}
   301  	resp, err := client.Do(req)
   302  	if err != nil {
   303  		return errors.Wrap(err, "failed to send HTTP request")
   304  	}
   305  	defer resp.Body.Close()
   306  
   307  	if resp.StatusCode != http.StatusOK {
   308  		errMsg, _ := io.ReadAll(resp.Body)
   309  		return fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   310  	}
   311  
   312  	_, err = io.ReadAll(resp.Body)
   313  	if err != nil {
   314  		return errors.Wrap(err, "failed to read response body")
   315  	}
   316  
   317  	return nil
   318  }
   319  
   320  func CallZvaultRevokeKey(serverAddr, token, clientID, publicKey string) error {
   321  	// Add your code here
   322  	endpoint := fmt.Sprintf("%s/revoke/%s?public_key=%s", serverAddr, clientID, publicKey)
   323  	req, err := http.NewRequest("POST", endpoint, nil)
   324  	if err != nil {
   325  		return errors.Wrap(err, "failed to create HTTP request")
   326  	}
   327  
   328  	fmt.Println("call zvault /revoke:", endpoint)
   329  	req.Header.Set("Content-Type", "application/json")
   330  	req.Header.Set("X-Jwt-Token", token)
   331  
   332  	client := &http.Client{}
   333  	resp, err := client.Do(req)
   334  	if err != nil {
   335  		return errors.Wrap(err, "failed to send HTTP request")
   336  	}
   337  	defer resp.Body.Close()
   338  
   339  	if resp.StatusCode != http.StatusOK {
   340  		errMsg, _ := io.ReadAll(resp.Body)
   341  		return fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   342  	}
   343  
   344  	_, err = io.ReadAll(resp.Body)
   345  	if err != nil {
   346  		return errors.Wrap(err, "failed to read response body")
   347  	}
   348  
   349  	return nil
   350  }
   351  
   352  func CallZvaultRetrieveWallets(serverAddr, token string) (string, error) {
   353  	// Add your code here
   354  	endpoint := fmt.Sprintf("%s/wallets", serverAddr)
   355  	req, err := http.NewRequest("GET", endpoint, nil)
   356  	if err != nil {
   357  		return "", errors.Wrap(err, "failed to create HTTP request")
   358  	}
   359  
   360  	fmt.Println("call zvault /keys:", endpoint)
   361  	req.Header.Set("Content-Type", "application/json")
   362  	req.Header.Set("X-Jwt-Token", token)
   363  
   364  	client := &http.Client{}
   365  	resp, err := client.Do(req)
   366  	if err != nil {
   367  		return "", errors.Wrap(err, "failed to send HTTP request")
   368  	}
   369  	defer resp.Body.Close()
   370  
   371  	if resp.StatusCode != http.StatusOK {
   372  		errMsg, _ := io.ReadAll(resp.Body)
   373  		return "", fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   374  	}
   375  
   376  	d, err := io.ReadAll(resp.Body)
   377  	if err != nil {
   378  		return "", errors.Wrap(err, "failed to read response body")
   379  	}
   380  
   381  	return string(d), nil
   382  }
   383  
   384  func CallZvaultRetrieveSharedWallets(serverAddr, token string) (string, error) {
   385  	// Add your code here
   386  	endpoint := fmt.Sprintf("%s/wallets/shared", serverAddr)
   387  	req, err := http.NewRequest("GET", endpoint, nil)
   388  	if err != nil {
   389  		return "", errors.Wrap(err, "failed to create HTTP request")
   390  	}
   391  
   392  	fmt.Println("call zvault /keys:", endpoint)
   393  	req.Header.Set("Content-Type", "application/json")
   394  	req.Header.Set("X-Jwt-Token", token)
   395  
   396  	client := &http.Client{}
   397  	resp, err := client.Do(req)
   398  	if err != nil {
   399  		return "", errors.Wrap(err, "failed to send HTTP request")
   400  	}
   401  	defer resp.Body.Close()
   402  
   403  	if resp.StatusCode != http.StatusOK {
   404  		errMsg, _ := io.ReadAll(resp.Body)
   405  		return "", fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg))
   406  	}
   407  
   408  	d, err := io.ReadAll(resp.Body)
   409  	if err != nil {
   410  		return "", errors.Wrap(err, "failed to read response body")
   411  	}
   412  
   413  	return string(d), nil
   414  }
   415  
   416  // ZauthSignTxn returns a function that sends a txn signing request to the zauth server
   417  func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc {
   418  	return func(msg string) (string, error) {
   419  		fmt.Println("zvault sign txn - in sign txn...")
   420  		req, err := http.NewRequest("POST", serverAddr+"/sign/txn", bytes.NewBuffer([]byte(msg)))
   421  		if err != nil {
   422  			return "", errors.Wrap(err, "failed to create HTTP request")
   423  		}
   424  		req.Header.Set("Content-Type", "application/json")
   425  		c := client.GetClient()
   426  		pubkey := c.Keys[0].PublicKey
   427  		req.Header.Set("X-Peer-Public-Key", pubkey)
   428  
   429  		client := &http.Client{}
   430  		resp, err := client.Do(req)
   431  		if err != nil {
   432  			return "", errors.Wrap(err, "failed to send HTTP request")
   433  		}
   434  		defer resp.Body.Close()
   435  		if resp.StatusCode != http.StatusOK {
   436  			rsp, err := io.ReadAll(resp.Body)
   437  			if err != nil {
   438  				return "", errors.Wrap(err, "failed to read response body")
   439  			}
   440  
   441  			return "", errors.Errorf("unexpected status code: %d, res: %s", resp.StatusCode, string(rsp))
   442  		}
   443  
   444  		d, err := io.ReadAll(resp.Body)
   445  		if err != nil {
   446  			return "", errors.Wrap(err, "failed to read response body")
   447  		}
   448  
   449  		return string(d), nil
   450  	}
   451  }
   452  
   453  func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc {
   454  	return func(msg string) (string, error) {
   455  		// return func(msg string) (string, error) {
   456  		req, err := http.NewRequest("POST", serverAddr+"/sign/msg", bytes.NewBuffer([]byte(msg)))
   457  		if err != nil {
   458  			return "", errors.Wrap(err, "failed to create HTTP request")
   459  		}
   460  
   461  		c := client.GetClient()
   462  		pubkey := c.Keys[0].PublicKey
   463  		req.Header.Set("Content-Type", "application/json")
   464  		req.Header.Set("X-Peer-Public-Key", pubkey)
   465  
   466  		client := &http.Client{}
   467  		resp, err := client.Do(req)
   468  		if err != nil {
   469  			return "", errors.Wrap(err, "failed to send HTTP request")
   470  		}
   471  		defer resp.Body.Close()
   472  		if resp.StatusCode != http.StatusOK {
   473  			rsp, err := io.ReadAll(resp.Body)
   474  			if err != nil {
   475  				return "", errors.Wrap(err, "failed to read response body")
   476  			}
   477  
   478  			return "", errors.Errorf("unexpected status code: %d, res: %s", resp.StatusCode, string(rsp))
   479  		}
   480  
   481  		d, err := io.ReadAll(resp.Body)
   482  		if err != nil {
   483  			return "", errors.Wrap(err, "failed to read response body")
   484  		}
   485  
   486  		return string(d), nil
   487  	}
   488  }
   489  
   490  type AuthMessage struct {
   491  	Hash      string `json:"hash"`
   492  	Signature string `json:"signature"`
   493  	ClientID  string `json:"client_id"`
   494  }
   495  
   496  type AuthResponse struct {
   497  	Sig string `json:"sig"`
   498  }
   499  
   500  func ZauthSignMsg(serverAddr string) sys.SignFunc {
   501  	return func(hash string, signatureScheme string, keys []sys.KeyPair) (string, error) {
   502  		sig, err := SignWithKey(keys[0].PrivateKey, hash)
   503  		if err != nil {
   504  			return "", err
   505  		}
   506  
   507  		data, err := json.Marshal(AuthMessage{
   508  			Hash:      hash,
   509  			Signature: sig,
   510  			ClientID:  client.GetClient().ClientID,
   511  		})
   512  		if err != nil {
   513  			return "", err
   514  		}
   515  
   516  		// fmt.Println("auth - sys.AuthCommon:", sys.AuthCommon)
   517  		if sys.AuthCommon == nil {
   518  			return "", errors.New("authCommon is not set")
   519  		}
   520  
   521  		rsp, err := sys.AuthCommon(string(data))
   522  		if err != nil {
   523  			return "", err
   524  		}
   525  
   526  		var ar AuthResponse
   527  		err = json.Unmarshal([]byte(rsp), &ar)
   528  		if err != nil {
   529  			return "", err
   530  		}
   531  
   532  		return AddSignature(client.GetClientPrivateKey(), ar.Sig, hash)
   533  	}
   534  }