Coinbase的“发送资金”API返回HTML BAD REQUEST响应(Go)

huangapple go评论83阅读模式
英文:

Coinbase "Send Money" API returns html BAD REQUEST response (Go)

问题

我正在尝试访问Coinbase的Send Money API端点,文档在这里,但是当我尝试使用时,我得到的是一个HTML响应,似乎表明Cloudflare正在阻止我,但我不确定:

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>

Coinbase的错误文档指出我应该得到实际的错误代码,但显然情况并非如此。

我尝试过的方法:

  1. 我找不到任何关于头部信息的信息,尝试使用VPN连接到其他地方也没有任何效果。
  2. 去掉我的API密钥/密钥头部会导致另一条错误消息作为JSON响应,指出我未经身份验证。
  3. 我已成功连接到其他端点(但目前只有GET请求)。
  4. 我确认我的API密钥的范围包括此端点所需的范围(wallet:transactions:send)。
  5. 我尝试从主帐户和特定帐户ID进行此请求,两者都会出现相同的错误。
  6. 我尝试修改POST请求有效负载的顺序,使其与文档匹配,或者按字母顺序排列,因为我以前在其他API中遇到过这个问题。

我一定是漏掉了一些非常明显的东西,但我似乎无法找出来或找到其他地方提到这个问题。

这是我用来发送请求的代码:

var (
	cbAPIKey    = os.Getenv("CB_API_KEY")
	cbAPISecret = os.Getenv("CB_API_SECRET")
    ethAccountID = os.Getenv("CB_ETH_ACCOUNT_ID")

	version = "2023-04-01" // https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/versioning
)

func TestSendEth(t *testing.T) {
	destination := "..."
	transaction, err := SendEth(destination, "0.1")
	assert.Nil(t, err)
	assert.Equal(t, destination, transaction.To.Address)
}

type sendPayload struct {
	Type        string  `json:"type"` // must be "send"
	To          string  `json:"to"`
	Amount      string  `json:"amount"`
	Currency    string  `json:"currency"`
	Description *string `json:"description,omitempty"`
	Idem        *string `json:"idem,omitempty"`
	// For select currencies, destination_tag or memo indicates the beneficiary or destination of a
	// payment for select currencies. Example:
	// { "type" : "send", "to":"address", "destination_tag" : "memo", "amount":"", "currency":"" }
	DestinationTag *string `json:"destination_tag,omitempty"`
}

func SendEth(to, amount string) (transaction Transaction, err error) {
	payload := sendPayload{
		Type:     "send",
		To:       to,
		Amount:   amount,
		Currency: "ETH",
	}

	// serialize payload
	b, _ := json.Marshal(payload)
	reader := bytes.NewReader(b)

	url := fmt.Sprintf(transactionsURL, ethAccountID)
	req, _ := http.NewRequest("POST", url, reader)
	req.Header.Set("Content-Type", "application/json")

	// sign request
	err = signRequest(req)
	if err != nil {
		return
	}

	// send request
	c := http.Client{}
	response, err := c.Do(req)
	if err != nil {
		return
	}

	var cbResponse Response[Transaction]
	responseBytes, _ := ioutil.ReadAll(response.Body)
	err = json.Unmarshal(responseBytes, &cbResponse)
	if err != nil {
		log.Warn(string(responseBytes))
		log.WithError(err).Error("Failed to unmarshal response")
		return
	}

	transaction = cbResponse.Data
	return
}

// signRequest modifies a http.Request to include the Coinbase-Auth-Signature
// headers. You can find more information about these headers here:
// https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication
func signRequest(req *http.Request) (err error) {
	reqTime := time.Now().Unix()

	/*
		The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the secret key on the
		prehash string timestamp + method + requestPath + body (where + represents string concatenation).

		timestamp is the same as the X-CB-ACCESS-TIMESTAMP header.
		method should be UPPER CASE.
		requestPath is the full path and query parameters of the URL, e.g.: /v2/exchange-rates?currency=USD.
	*/
	body := "";

	if req.Body != nil {
		var bytes []byte
		bytes, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return
		}
		body = string(bytes)
	}

	message := fmt.Sprintf("%d%s%s%s", reqTime, req.Method, req.URL.Path, body)

	// generate a sha256 HMAC using the secret key on the prehash string
	signature := generateHMAC(message, cbAPISecret)

	req.Header.Set("CB-ACCESS-KEY", cbAPIKey)
	req.Header.Set("CB-ACCESS-SIGN", signature)
	req.Header.Set("CB-ACCESS-TIMESTAMP", fmt.Sprintf("%d", reqTime))
	req.Header.Set("CB-VERSION", version)

	return
}

我期望如果我做错了什么,至少应该得到错误消息来指示某种失败。但是我得到的是上述提到的不透明的Cloudflare错误。非常感谢任何帮助!

英文:

I am trying to access coinbase's Send Money api endpoint documented here but when I try it out, I am getting back an html response which seems to indicate cloudflare is blocking me but I'm not sure:

&lt;html&gt;
&lt;head&gt;&lt;title&gt;400 Bad Request&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;center&gt;&lt;h1&gt;400 Bad Request&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;cloudflare&lt;/center&gt;
&lt;/body&gt;

Coinbase's error documention states I should be getting back actual error codes but clearly that isn't the case

What I've tried:

  1. There's no info I can find in headers, trying a VPN to another place doesn't do anything.
  2. Taking away my api key/secret headers leads to another error message as a JSON response stating I am not authenticated
  3. I have successfully connected to other endpoints (but only GET request so far)
  4. I have confirmed the scope of my api key covers the one needed for this endpoint (wallet:transactions:send)
  5. I attempted making this request both from a primary account and from a specific account id, both give the same error.
  6. I've tried modifying the order of the post request payload so that it matches documentation, or so that it is in alphabetical order since I've hit that issue before with other apis in the past

I must be missing something really obvious here, but I can't seem to figure it out or find any mention of this issue elsewhere

Here's what I'm using to make my requests:

var (
cbAPIKey    = os.Getenv(&quot;CB_API_KEY&quot;)
cbAPISecret = os.Getenv(&quot;CB_API_SECRET&quot;)
ethAccountID = os.Getenv(&quot;CB_ETH_ACCOUNT_ID&quot;)
version = &quot;2023-04-01&quot; // https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/versioning
)
func TestSendEth(t *testing.T) {
destination := &quot;...&quot;
transaction, err := SendEth(destination, &quot;0.1&quot;)
assert.Nil(t, err)
assert.Equal(t, destination, transaction.To.Address)
}
type sendPayload struct {
Type        string  `json:&quot;type&quot;` // must be &quot;send&quot;
To          string  `json:&quot;to&quot;`
Amount      string  `json:&quot;amount&quot;`
Currency    string  `json:&quot;currency&quot;`
Description *string `json:&quot;description,omitempty&quot;`
Idem        *string `json:&quot;idem,omitempty&quot;`
// For select currencies, destination_tag or memo indicates the beneficiary or destination of a
// payment for select currencies. Example:
// { &quot;type&quot; : &quot;send&quot;, &quot;to&quot;: &quot;address&quot;, &quot;destination_tag&quot; : &quot;memo&quot;, &quot;amount&quot;: &quot;&quot;, &quot;currency&quot;: &quot;&quot; }
DestinationTag *string `json:&quot;destination_tag,omitempty&quot;`
}
func SendEth(to, amount string) (transaction Transaction, err error) {
payload := sendPayload{
Type:     &quot;send&quot;,
To:       to,
Amount:   amount,
Currency: &quot;ETH&quot;,
}
// serialize payload
b, _ := json.Marshal(payload)
reader := bytes.NewReader(b)
url := fmt.Sprintf(transactionsURL, ethAccountID)
req, _ := http.NewRequest(&quot;POST&quot;, url, reader)
req.Header.Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
// sign request
err = signRequest(req)
if err != nil {
return
}
// send request
c := http.Client{}
response, err := c.Do(req)
if err != nil {
return
}
var cbResponse Response[Transaction]
responseBytes, _ := ioutil.ReadAll(response.Body)
err = json.Unmarshal(responseBytes, &amp;cbResponse)
if err != nil {
log.Warn(string(responseBytes))
log.WithError(err).Error(&quot;Failed to unmarshal response&quot;)
return
}
transaction = cbResponse.Data
return
}
// signRequest modifies a http.Request to include the Coinbase-Auth-Signature
// headers. You can find more information about these headers here:
// https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication
func signRequest(req *http.Request) (err error) {
reqTime := time.Now().Unix()
/*
The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the secret key on the
prehash string timestamp + method + requestPath + body (where + represents string concatenation).
timestamp is the same as the X-CB-ACCESS-TIMESTAMP header.
method should be UPPER CASE.
requestPath is the full path and query parameters of the URL, e.g.: /v2/exchange-rates?currency=USD.
*/
body := &quot;&quot;
if req.Body != nil {
var bytes []byte
bytes, err = ioutil.ReadAll(req.Body)
if err != nil {
return
}
body = string(bytes)
}
message := fmt.Sprintf(&quot;%d%s%s%s&quot;, reqTime, req.Method, req.URL.Path, body)
// generate a sha256 HMAC using the secret key on the prehash string
signature := generateHMAC(message, cbAPISecret)
req.Header.Set(&quot;CB-ACCESS-KEY&quot;, cbAPIKey)
req.Header.Set(&quot;CB-ACCESS-SIGN&quot;, signature)
req.Header.Set(&quot;CB-ACCESS-TIMESTAMP&quot;, fmt.Sprintf(&quot;%d&quot;, reqTime))
req.Header.Set(&quot;CB-VERSION&quot;, version)
return
}

I'd expect that if I'm doing something wrong, I should at least get error messages back to indicate some kind of failure. But instead I get the mentioned opaque cloudflare failure. Any help would be greatly appreciated!

答案1

得分: 1

可能是由于缺少或错误的User-Agent标头,Cloudflare阻止了您的请求。要解决此问题,请尝试为您的HTTP请求设置一个User-Agent标头:

req.Header.Set("User-Agent", "MyAppName/1.0")

将MyAppName/1.0替换为适合您的应用程序的合适值。包括User-Agent可以帮助避免被Cloudflare阻止。

此外,请仔细检查终端点URL,确保其正确且完整。

有关Cloudflare问题和故障排除的详细信息,请参考Cloudflare支持。

如果问题仍然存在,直接联系Coinbase API支持可能会有帮助。您可以通过https://www.coinbase.com/cloud与他们的支持团队联系。

英文:

It's possible that Cloudflare is blocking your request due to a missing or incorrect User-Agent header. To fix this issue, try setting a User-Agent header for your HTTP request:

req.Header.Set(&quot;User-Agent&quot;, &quot;MyAppName/1.0&quot;)

Replace MyAppName/1.0 with a suitable value for your app. Including a User-Agent can help avoid being blocked by Cloudflare.

Additionally, double-check the endpoint URL to ensure it is correct and complete.

For further details on Cloudflare issues and troubleshooting, please refer to Cloudflare Support.

If the issue persists, it might be helpful to contact Coinbase API support directly. You can reach out to their support through the https://www.coinbase.com/cloud

huangapple
  • 本文由 发表于 2023年4月2日 04:51:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75908787.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定