mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-23 17:51:39 +00:00
2582 Enable CORS on RPC API (#2800)
This commit is contained in:
committed by
Anton Kaliaev
parent
3af11c43f2
commit
6353862ac0
@ -22,6 +22,8 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
|
|||||||
|
|
||||||
### FEATURES:
|
### FEATURES:
|
||||||
|
|
||||||
|
- [rpc] [\#2582](https://github.com/tendermint/tendermint/issues/2582) Enable CORS on RPC API
|
||||||
|
|
||||||
### IMPROVEMENTS:
|
### IMPROVEMENTS:
|
||||||
|
|
||||||
### BUG FIXES:
|
### BUG FIXES:
|
||||||
|
8
Gopkg.lock
generated
8
Gopkg.lock
generated
@ -128,6 +128,14 @@
|
|||||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758"
|
||||||
|
name = "github.com/rs/cors"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "9a47f48565a795472d43519dd49aac781f3034fb"
|
||||||
|
version = "v1.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
|
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
|
||||||
name = "github.com/hashicorp/hcl"
|
name = "github.com/hashicorp/hcl"
|
||||||
|
@ -40,6 +40,10 @@
|
|||||||
name = "github.com/gorilla/websocket"
|
name = "github.com/gorilla/websocket"
|
||||||
version = "=1.2.0"
|
version = "=1.2.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/rs/cors"
|
||||||
|
version = "1.6.0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/pkg/errors"
|
name = "github.com/pkg/errors"
|
||||||
version = "=0.8.0"
|
version = "=0.8.0"
|
||||||
|
@ -242,6 +242,18 @@ type RPCConfig struct {
|
|||||||
// TCP or UNIX socket address for the RPC server to listen on
|
// TCP or UNIX socket address for the RPC server to listen on
|
||||||
ListenAddress string `mapstructure:"laddr"`
|
ListenAddress string `mapstructure:"laddr"`
|
||||||
|
|
||||||
|
// A list of origins a cross-domain request can be executed from.
|
||||||
|
// If the special '*' value is present in the list, all origins will be allowed.
|
||||||
|
// An origin may contain a wildcard (*) to replace 0 or more characters (i.e.: http://*.domain.com).
|
||||||
|
// Only one wildcard can be used per origin.
|
||||||
|
CORSAllowedOrigins []string `mapstructure:"cors_allowed_origins"`
|
||||||
|
|
||||||
|
// A list of methods the client is allowed to use with cross-domain requests.
|
||||||
|
CORSAllowedMethods []string `mapstructure:"cors_allowed_methods"`
|
||||||
|
|
||||||
|
// A list of non simple headers the client is allowed to use with cross-domain requests.
|
||||||
|
CORSAllowedHeaders []string `mapstructure:"cors_allowed_headers"`
|
||||||
|
|
||||||
// TCP or UNIX socket address for the gRPC server to listen on
|
// TCP or UNIX socket address for the gRPC server to listen on
|
||||||
// NOTE: This server only supports /broadcast_tx_commit
|
// NOTE: This server only supports /broadcast_tx_commit
|
||||||
GRPCListenAddress string `mapstructure:"grpc_laddr"`
|
GRPCListenAddress string `mapstructure:"grpc_laddr"`
|
||||||
@ -270,7 +282,9 @@ type RPCConfig struct {
|
|||||||
func DefaultRPCConfig() *RPCConfig {
|
func DefaultRPCConfig() *RPCConfig {
|
||||||
return &RPCConfig{
|
return &RPCConfig{
|
||||||
ListenAddress: "tcp://0.0.0.0:26657",
|
ListenAddress: "tcp://0.0.0.0:26657",
|
||||||
|
CORSAllowedOrigins: []string{},
|
||||||
|
CORSAllowedMethods: []string{"HEAD", "GET", "POST"},
|
||||||
|
CORSAllowedHeaders: []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time"},
|
||||||
GRPCListenAddress: "",
|
GRPCListenAddress: "",
|
||||||
GRPCMaxOpenConnections: 900,
|
GRPCMaxOpenConnections: 900,
|
||||||
|
|
||||||
@ -300,6 +314,11 @@ func (cfg *RPCConfig) ValidateBasic() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsCorsEnabled returns true if cross-origin resource sharing is enabled.
|
||||||
|
func (cfg *RPCConfig) IsCorsEnabled() bool {
|
||||||
|
return len(cfg.CORSAllowedOrigins) != 0
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// P2PConfig
|
// P2PConfig
|
||||||
|
|
||||||
|
@ -119,6 +119,17 @@ filter_peers = {{ .BaseConfig.FilterPeers }}
|
|||||||
# TCP or UNIX socket address for the RPC server to listen on
|
# TCP or UNIX socket address for the RPC server to listen on
|
||||||
laddr = "{{ .RPC.ListenAddress }}"
|
laddr = "{{ .RPC.ListenAddress }}"
|
||||||
|
|
||||||
|
# A list of origins a cross-domain request can be executed from
|
||||||
|
# Default value '[]' disables cors support
|
||||||
|
# Use '["*"]' to allow any origin
|
||||||
|
cors_allowed_origins = "{{ .RPC.CORSAllowedOrigins }}"
|
||||||
|
|
||||||
|
# A list of methods the client is allowed to use with cross-domain requests
|
||||||
|
cors_allowed_methods = "{{ .RPC.CORSAllowedMethods }}"
|
||||||
|
|
||||||
|
# A list of non simple headers the client is allowed to use with cross-domain requests
|
||||||
|
cors_allowed_headers = "{{ .RPC.CORSAllowedHeaders }}"
|
||||||
|
|
||||||
# TCP or UNIX socket address for the gRPC server to listen on
|
# TCP or UNIX socket address for the gRPC server to listen on
|
||||||
# NOTE: This server only supports /broadcast_tx_commit
|
# NOTE: This server only supports /broadcast_tx_commit
|
||||||
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"
|
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"
|
||||||
|
16
node/node.go
16
node/node.go
@ -13,8 +13,9 @@ import (
|
|||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/rs/cors"
|
||||||
|
|
||||||
amino "github.com/tendermint/go-amino"
|
"github.com/tendermint/go-amino"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
bc "github.com/tendermint/tendermint/blockchain"
|
bc "github.com/tendermint/tendermint/blockchain"
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
@ -651,9 +652,20 @@ func (n *Node) startRPC() ([]net.Listener, error) {
|
|||||||
wm.SetLogger(rpcLogger.With("protocol", "websocket"))
|
wm.SetLogger(rpcLogger.With("protocol", "websocket"))
|
||||||
mux.HandleFunc("/websocket", wm.WebsocketHandler)
|
mux.HandleFunc("/websocket", wm.WebsocketHandler)
|
||||||
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)
|
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)
|
||||||
|
|
||||||
|
var rootHandler http.Handler = mux
|
||||||
|
if n.config.RPC.IsCorsEnabled() {
|
||||||
|
corsMiddleware := cors.New(cors.Options{
|
||||||
|
AllowedOrigins: n.config.RPC.CORSAllowedOrigins,
|
||||||
|
AllowedMethods: n.config.RPC.CORSAllowedMethods,
|
||||||
|
AllowedHeaders: n.config.RPC.CORSAllowedHeaders,
|
||||||
|
})
|
||||||
|
rootHandler = corsMiddleware.Handler(mux)
|
||||||
|
}
|
||||||
|
|
||||||
listener, err := rpcserver.StartHTTPServer(
|
listener, err := rpcserver.StartHTTPServer(
|
||||||
listenAddr,
|
listenAddr,
|
||||||
mux,
|
rootHandler,
|
||||||
rpcLogger,
|
rpcLogger,
|
||||||
rpcserver.Config{MaxOpenConnections: n.config.RPC.MaxOpenConnections},
|
rpcserver.Config{MaxOpenConnections: n.config.RPC.MaxOpenConnections},
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,7 @@ package client_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ import (
|
|||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/rpc/client"
|
"github.com/tendermint/tendermint/rpc/client"
|
||||||
rpctest "github.com/tendermint/tendermint/rpc/test"
|
"github.com/tendermint/tendermint/rpc/test"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,6 +33,21 @@ func GetClients() []client.Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCorsEnabled(t *testing.T) {
|
||||||
|
origin := rpctest.GetConfig().RPC.CORSAllowedOrigins[0]
|
||||||
|
remote := strings.Replace(rpctest.GetConfig().RPC.ListenAddress, "tcp", "http", -1)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", remote, nil)
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
req.Header.Set("Origin", origin)
|
||||||
|
c := &http.Client{}
|
||||||
|
resp, err := c.Do(req)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
assert.Equal(t, resp.Header.Get("Access-Control-Allow-Origin"), origin)
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure status is correct (we connect properly)
|
// Make sure status is correct (we connect properly)
|
||||||
func TestStatus(t *testing.T) {
|
func TestStatus(t *testing.T) {
|
||||||
for i, c := range GetClients() {
|
for i, c := range GetClients() {
|
||||||
|
@ -12,7 +12,10 @@ See it here: https://github.com/tendermint/tendermint/tree/master/rpc/lib
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Set the `laddr` config parameter under `[rpc]` table in the `$TMHOME/config/config.toml` file or the `--rpc.laddr` command-line flag to the desired protocol://host:port setting. Default: `tcp://0.0.0.0:26657`.
|
RPC can be configured by tuning parameters under `[rpc]` table in the `$TMHOME/config/config.toml` file or by using the `--rpc.X` command-line flags.
|
||||||
|
|
||||||
|
Default rpc listen address is `tcp://0.0.0.0:26657`. To set another address, set the `laddr` config parameter to desired value.
|
||||||
|
CORS (Cross-Origin Resource Sharing) can be enabled by setting `cors_allowed_origins`, `cors_allowed_methods`, `cors_allowed_headers` config parameters.
|
||||||
|
|
||||||
## Arguments
|
## Arguments
|
||||||
|
|
||||||
|
@ -151,11 +151,6 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler
|
|||||||
rww := &ResponseWriterWrapper{-1, w}
|
rww := &ResponseWriterWrapper{-1, w}
|
||||||
begin := time.Now()
|
begin := time.Now()
|
||||||
|
|
||||||
// Common headers
|
|
||||||
origin := r.Header.Get("Origin")
|
|
||||||
rww.Header().Set("Access-Control-Allow-Origin", origin)
|
|
||||||
rww.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
||||||
rww.Header().Set("Access-Control-Expose-Headers", "X-Server-Time")
|
|
||||||
rww.Header().Set("X-Server-Time", fmt.Sprintf("%v", begin.Unix()))
|
rww.Header().Set("X-Server-Time", fmt.Sprintf("%v", begin.Unix()))
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -84,6 +84,7 @@ func GetConfig() *cfg.Config {
|
|||||||
tm, rpc, grpc := makeAddrs()
|
tm, rpc, grpc := makeAddrs()
|
||||||
globalConfig.P2P.ListenAddress = tm
|
globalConfig.P2P.ListenAddress = tm
|
||||||
globalConfig.RPC.ListenAddress = rpc
|
globalConfig.RPC.ListenAddress = rpc
|
||||||
|
globalConfig.RPC.CORSAllowedOrigins = []string{"https://tendermint.com/"}
|
||||||
globalConfig.RPC.GRPCListenAddress = grpc
|
globalConfig.RPC.GRPCListenAddress = grpc
|
||||||
globalConfig.TxIndex.IndexTags = "app.creator,tx.height" // see kvstore application
|
globalConfig.TxIndex.IndexTags = "app.creator,tx.height" // see kvstore application
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user