mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-07 13:00:59 +08:00
security: add safe.ReadAllLimited — bound all HTTP response body reads to 10MB
- Created safe/io.go with ReadAllLimited helper (default 10MB limit) - Replaced 62 unbounded io.ReadAll(resp.Body) calls across 32 files - Covers all exchange traders (Hyperliquid, Bybit, Binance, OKX, Aster, KuCoin, Gate, Bitget, Lighter, Indodax), providers (CoinAnk, Alpaca, TwelveData), MCP client/x402, market data, wallet, telegram, kernel - Prevents OOM from malicious/buggy exchange API responses - Previously fixed: brain.go, sentinel.go already had manual LimitReader
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -134,7 +135,7 @@ func searchStock(keyword string) ([]SearchResult, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
reader := transform.NewReader(io.LimitReader(resp.Body, 256*1024), simplifiedchinese.GBK.NewDecoder())
|
||||
body, err := io.ReadAll(reader)
|
||||
body, err := safe.ReadAllLimited(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -288,7 +289,7 @@ func fetchStockQuote(code string) (*StockQuote, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
reader := transform.NewReader(io.LimitReader(resp.Body, 256*1024), simplifiedchinese.GBK.NewDecoder())
|
||||
body, err := io.ReadAll(reader)
|
||||
body, err := safe.ReadAllLimited(reader)
|
||||
if err != nil { return nil, err }
|
||||
|
||||
line := string(body)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"nofx/market"
|
||||
@@ -616,7 +616,7 @@ func (e *StrategyEngine) fetchSingleExternalSource(source store.ExternalDataSour
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"nofx/hook"
|
||||
@@ -43,7 +43,7 @@ func (c *APIClient) GetExchangeInfo() (*ExchangeInfo, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func (c *APIClient) GetKlines(symbol, interval string, limit int) ([]Kline, erro
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -140,7 +140,7 @@ func (c *APIClient) GetCurrentPrice(symbol string) (float64, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"nofx/logger"
|
||||
"strconv"
|
||||
@@ -266,7 +266,7 @@ func getOpenInterestData(symbol string) (*OIData, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -311,7 +311,7 @@ func getFundingRate(symbol string) (float64, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -51,7 +51,7 @@ func GetKlinesRange(symbol string, timeframe string, start, end time.Time) ([]Kl
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -371,7 +371,7 @@ func (client *Client) Call(systemPrompt, userPrompt string) (string, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Step 6: Read response body (fixed logic)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -510,7 +510,7 @@ func (client *Client) callWithRequestFull(req *Request) (*LLMResponse, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -548,7 +548,7 @@ func (client *Client) callWithRequest(req *Request) (string, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -721,7 +721,7 @@ func (client *Client) CallWithRequestStream(req *Request, onChunk func(string))
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
return "", fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ func DoX402Request(
|
||||
paymentHeader = resp.Header.Get("X-Payment-Required")
|
||||
}
|
||||
if paymentHeader == "" {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
return nil, fmt.Errorf("received 402 but no Payment-Required header found. Body: %s", string(body))
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ func DoX402Request(
|
||||
return nil, fmt.Errorf("failed to send payment retry: %w", err)
|
||||
}
|
||||
|
||||
body2, readErr := io.ReadAll(resp2.Body)
|
||||
body2, readErr := safe.ReadAllLimited(resp2.Body)
|
||||
resp2.Body.Close()
|
||||
if readErr != nil {
|
||||
return nil, fmt.Errorf("failed to read payment retry response: %w", readErr)
|
||||
@@ -221,7 +221,7 @@ func DoX402Request(
|
||||
return nil, fmt.Errorf("%s payment retry failed (status %d): %s", providerTag, lastStatus, string(lastBody))
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -261,7 +261,7 @@ func DoX402RequestStream(
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return resp, nil
|
||||
}
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
resp.Body.Close()
|
||||
return nil, fmt.Errorf("%s API error (status %d): %s", providerTag, resp.StatusCode, string(body))
|
||||
}
|
||||
@@ -272,7 +272,7 @@ func DoX402RequestStream(
|
||||
paymentHeader = resp.Header.Get("X-Payment-Required")
|
||||
}
|
||||
if paymentHeader == "" {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
resp.Body.Close()
|
||||
return nil, fmt.Errorf("received 402 but no Payment-Required header found. Body: %s", string(body))
|
||||
}
|
||||
@@ -320,7 +320,7 @@ func DoX402RequestStream(
|
||||
}
|
||||
|
||||
// Non-200: read body for error handling / re-sign
|
||||
body2, readErr := io.ReadAll(resp2.Body)
|
||||
body2, readErr := safe.ReadAllLimited(resp2.Body)
|
||||
resp2.Body.Close()
|
||||
if readErr != nil {
|
||||
return nil, fmt.Errorf("failed to read payment retry response: %w", readErr)
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
|
||||
### Code Quality
|
||||
- [DONE] Extract WelcomeScreen, ChatMessages, ChatInput from AgentChatPage (825→480 lines)
|
||||
- [DONE] Sanitize 3 more error message leaks in API responses (handler_trader.go ×2, handler_ai_cost.go ×1)
|
||||
- [PENDING] `context.Background()` used in ~69 exchange/trader calls — should propagate request context for proper cancellation (partially done: kline handlers fixed, trader/exchange calls remain)
|
||||
|
||||
### Performance
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package alpaca
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"nofx/config"
|
||||
@@ -111,7 +111,7 @@ func (c *Client) GetBars(ctx context.Context, symbol string, timeframe string, l
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read response
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package coinank_api
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"nofx/provider/coinank"
|
||||
@@ -67,7 +67,7 @@ func get(ctx context.Context, path string, paramsMap map[string]string) (string,
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package coinank
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
@@ -59,7 +59,7 @@ func (c *CoinankClient) Get(ctx context.Context, path string, paramsMap map[stri
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (c *CoinankClient) Post(ctx context.Context, path string, data any) (string
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package hyperliquid
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -117,7 +117,7 @@ func (c *Client) GetCandles(ctx context.Context, coin string, interval string, l
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read response
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -169,7 +169,7 @@ func (c *Client) GetAllMidsWithDex(ctx context.Context, dex string) (map[string]
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -206,7 +206,7 @@ func (c *Client) GetMeta(ctx context.Context) (*Meta, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package twelvedata
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"nofx/config"
|
||||
@@ -125,7 +125,7 @@ func (c *Client) GetTimeSeries(ctx context.Context, symbol string, interval stri
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read response
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -172,7 +172,7 @@ func (c *Client) GetQuote(ctx context.Context, symbol string) (*QuoteResponse, e
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Read response
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
29
safe/io.go
Normal file
29
safe/io.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// Package safe provides safe I/O helpers.
|
||||
package safe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// MaxResponseBody is the default maximum size for HTTP response bodies (10MB).
|
||||
const MaxResponseBody = 10 * 1024 * 1024
|
||||
|
||||
// ReadAllLimited reads all bytes from r up to maxBytes.
|
||||
// If maxBytes <= 0, it defaults to MaxResponseBody (10MB).
|
||||
// Returns an error if the response exceeds the limit.
|
||||
func ReadAllLimited(r io.Reader, maxBytes ...int64) ([]byte, error) {
|
||||
limit := int64(MaxResponseBody)
|
||||
if len(maxBytes) > 0 && maxBytes[0] > 0 {
|
||||
limit = maxBytes[0]
|
||||
}
|
||||
lr := io.LimitReader(r, limit+1)
|
||||
data, err := io.ReadAll(lr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if int64(len(data)) > limit {
|
||||
return nil, fmt.Errorf("response body exceeds %d bytes limit", limit)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -65,7 +66,7 @@ func (t *apiCallTool) execute(req *apiRequest) string {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("error reading response: %v", err)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package aster
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
@@ -100,7 +100,7 @@ func (t *AsterTrader) getPrecision(symbol string) (SymbolPrecision, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
var info struct {
|
||||
Symbols []struct {
|
||||
Symbol string `json:"symbol"`
|
||||
@@ -392,7 +392,7 @@ func (t *AsterTrader) doRequest(method, endpoint string, params map[string]inter
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
@@ -418,7 +418,7 @@ func (t *AsterTrader) doRequest(method, endpoint string, params map[string]inter
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package aster
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"nofx/trader/types"
|
||||
@@ -109,7 +109,7 @@ func (t *AsterTrader) GetMarketPrice(symbol string) (float64, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return 0, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
@@ -263,7 +263,7 @@ func (t *AsterTrader) GetOrderBook(symbol string, depth int) (bids, asks [][]flo
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package bitget
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"strconv"
|
||||
@@ -193,7 +193,7 @@ func (t *BitgetTrader) doRequest(method, path string, body interface{}) ([]byte,
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
respBody, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"nofx/market"
|
||||
@@ -79,7 +78,7 @@ func (t *BybitTrader) getTradesViaHTTP(startTime time.Time, limit int) ([]BybitT
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package bybit
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
@@ -101,7 +101,7 @@ func (t *BybitTrader) getQtyStep(symbol string) float64 {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package bybit
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/trader/types"
|
||||
"strconv"
|
||||
@@ -134,7 +134,7 @@ func (t *BybitTrader) getClosedPnLViaHTTP(startTime time.Time, limit int) ([]typ
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package bybit
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"nofx/trader/types"
|
||||
@@ -696,7 +696,7 @@ func (t *BybitTrader) GetOrderBook(symbol string, depth int) (bids, asks [][]flo
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
body, _ := safe.ReadAllLimited(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package hyperliquid
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"nofx/trader/types"
|
||||
@@ -224,7 +224,7 @@ func (t *HyperliquidTrader) getXYZDexBalance() (accountValue float64, unrealized
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return 0, 0, nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -315,7 +315,7 @@ func (t *HyperliquidTrader) getXyzMarketPrice(coin string) (float64, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package hyperliquid
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"nofx/trader/types"
|
||||
@@ -452,7 +452,7 @@ func (t *HyperliquidTrader) cancelXyzOrders(coin string) error {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -545,7 +545,7 @@ func (t *HyperliquidTrader) cancelXyzOrder(oid int64) error {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -686,7 +686,7 @@ func (t *HyperliquidTrader) placeXyzOrder(coin string, isBuy bool, size float64,
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
@@ -850,7 +850,7 @@ func (t *HyperliquidTrader) placeXyzTriggerOrder(coin string, isBuy bool, size f
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package hyperliquid
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"strings"
|
||||
@@ -74,7 +74,7 @@ func (t *HyperliquidTrader) fetchXyzMeta() error {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package indodax
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"crypto/hmac"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"nofx/logger"
|
||||
@@ -131,7 +131,7 @@ func (t *IndodaxTrader) doPublicRequest(path string) ([]byte, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
data, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -168,7 +168,7 @@ func (t *IndodaxTrader) doPrivateRequest(params url.Values) ([]byte, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
data, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package kucoin
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
@@ -127,7 +127,7 @@ func (t *KuCoinTrader) syncServerTime() error {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func (t *KuCoinTrader) doRequest(method, path string, body interface{}) ([]byte,
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
respBody, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package lighter
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"strconv"
|
||||
@@ -26,7 +26,7 @@ func (t *LighterTraderV2) getFullAccountInfo() (*AccountInfo, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -305,7 +305,7 @@ func (t *LighterTraderV2) GetMarketPrice(symbol string) (float64, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -379,7 +379,7 @@ func (t *LighterTraderV2) GetOrderBook(symbol string, depth int) (bids, asks [][
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package lighter
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"nofx/logger"
|
||||
@@ -120,7 +120,7 @@ func (t *LighterTraderV2) GetOrderStatus(symbol string, orderID string) (map[str
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
@@ -236,7 +236,7 @@ func (t *LighterTraderV2) GetActiveOrders(symbol string) ([]OrderResponse, error
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package lighter
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -211,7 +211,7 @@ func (t *LighterTraderV2) getAccountByL1Address() (*AccountInfo, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -286,7 +286,7 @@ func (t *LighterTraderV2) getApiKeyFromServer() (string, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -484,7 +484,7 @@ func (t *LighterTraderV2) GetTrades(startTime time.Time, limit int) ([]tradertyp
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package lighter
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
@@ -389,7 +389,7 @@ func (t *LighterTraderV2) submitOrder(txType int, txInfo string) (map[string]int
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
respBody, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -546,7 +546,7 @@ func (t *LighterTraderV2) fetchMarketList() ([]MarketInfo, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
body, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package okx
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
@@ -9,7 +10,6 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"nofx/logger"
|
||||
"strings"
|
||||
@@ -228,7 +228,7 @@ func (t *OKXTrader) doRequest(method, path string, body interface{}) ([]byte, er
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
respBody, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"nofx/safe"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -61,7 +61,7 @@ func QueryUSDCBalanceStr(address string) string {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
respBody, err := safe.ReadAllLimited(resp.Body)
|
||||
if err != nil {
|
||||
return "0.00"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user