Skip to content

Commit b19dd47

Browse files
committedAug 2, 2015
Merge pull request #1544 from ipfs/fix/allowed-origins
fix allowed origins to make webui work again
2 parents d50def3 + 3ee83a7 commit b19dd47

11 files changed

+104
-40
lines changed
 

‎cmd/ipfs/daemon.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
_ "expvar"
55
"fmt"
6+
"net"
67
"net/http"
78
_ "net/http/pprof"
89
"os"
@@ -126,8 +127,8 @@ future version, along with this notice. Please move to setting the HTTP Headers.
126127
// mostly useful to hook up things that register in the default muxer,
127128
// and don't provide a convenient http.Handler entry point, such as
128129
// expvar and http/pprof.
129-
func defaultMux(path string) func(node *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
130-
return func(node *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
130+
func defaultMux(path string) corehttp.ServeOption {
131+
return func(node *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
131132
mux.Handle(path, http.DefaultServeMux)
132133
return mux, nil
133134
}

‎commands/http/handler.go

+13-23
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"net/http"
9+
"net/url"
910
"strconv"
1011
"strings"
1112

@@ -55,13 +56,6 @@ const (
5556
ACACredentials = "Access-Control-Allow-Credentials"
5657
)
5758

58-
var localhostOrigins = []string{
59-
"http://127.0.0.1",
60-
"https://127.0.0.1",
61-
"http://localhost",
62-
"https://localhost",
63-
}
64-
6559
var mimeTypes = map[string]string{
6660
cmds.JSON: "application/json",
6761
cmds.XML: "application/xml",
@@ -91,21 +85,7 @@ func skipAPIHeader(h string) bool {
9185

9286
func NewHandler(ctx cmds.Context, root *cmds.Command, cfg *ServerConfig) *Handler {
9387
if cfg == nil {
94-
cfg = &ServerConfig{}
95-
}
96-
97-
if cfg.CORSOpts == nil {
98-
cfg.CORSOpts = new(cors.Options)
99-
}
100-
101-
// by default, use GET, PUT, POST
102-
if cfg.CORSOpts.AllowedMethods == nil {
103-
cfg.CORSOpts.AllowedMethods = []string{"GET", "POST", "PUT"}
104-
}
105-
106-
// by default, only let 127.0.0.1 through.
107-
if cfg.CORSOpts.AllowedOrigins == nil {
108-
cfg.CORSOpts.AllowedOrigins = localhostOrigins
88+
panic("must provide a valid ServerConfig")
10989
}
11090

11191
// Wrap the internal handler with CORS handling-middleware.
@@ -375,6 +355,16 @@ func allowReferer(r *http.Request, cfg *ServerConfig) bool {
375355
return true
376356
}
377357

358+
u, err := url.Parse(referer)
359+
if err != nil {
360+
// bad referer. but there _is_ something, so bail.
361+
log.Debug("failed to parse referer: ", referer)
362+
// debug because referer comes straight from the client. dont want to
363+
// let people DOS by putting a huge referer that gets stored in log files.
364+
return false
365+
}
366+
origin := u.Scheme + "://" + u.Host
367+
378368
// check CORS ACAOs and pretend Referer works like an origin.
379369
// this is valid for many (most?) sane uses of the API in
380370
// other applications, and will have the desired effect.
@@ -384,7 +374,7 @@ func allowReferer(r *http.Request, cfg *ServerConfig) bool {
384374
}
385375

386376
// referer is allowed explicitly
387-
if o == referer {
377+
if o == origin {
388378
return true
389379
}
390380
}

‎commands/http/handler_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func originCfg(origins []string) *ServerConfig {
3131
return &ServerConfig{
3232
CORSOpts: &cors.Options{
3333
AllowedOrigins: origins,
34+
AllowedMethods: []string{"GET", "PUT", "POST"},
3435
},
3536
}
3637
}
@@ -46,6 +47,13 @@ type testCase struct {
4647
ResHeaders map[string]string
4748
}
4849

50+
var defaultOrigins = []string{
51+
"http://localhost",
52+
"http://127.0.0.1",
53+
"https://localhost",
54+
"https://127.0.0.1",
55+
}
56+
4957
func getTestServer(t *testing.T, origins []string) *httptest.Server {
5058
cmdsCtx, err := coremock.MockCmdsCtx()
5159
if err != nil {
@@ -59,6 +67,10 @@ func getTestServer(t *testing.T, origins []string) *httptest.Server {
5967
},
6068
}
6169

70+
if len(origins) == 0 {
71+
origins = defaultOrigins
72+
}
73+
6274
handler := NewHandler(cmdsCtx, cmdRoot, originCfg(origins))
6375
return httptest.NewServer(handler)
6476
}

‎core/corehttp/commands.go

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package corehttp
22

33
import (
4+
"net"
45
"net/http"
56
"os"
7+
"strconv"
68
"strings"
79

810
cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
@@ -28,6 +30,13 @@ or
2830
ipfs daemon --api-http-header 'Access-Control-Allow-Origin: *'
2931
`
3032

33+
var defaultLocalhostOrigins = []string{
34+
"http://127.0.0.1:<port>",
35+
"https://127.0.0.1:<port>",
36+
"http://localhost:<port>",
37+
"https://localhost:<port>",
38+
}
39+
3140
func addCORSFromEnv(c *cmdsHttp.ServerConfig) {
3241
origin := os.Getenv(originEnvKey)
3342
if origin != "" {
@@ -57,8 +66,41 @@ func addHeadersFromConfig(c *cmdsHttp.ServerConfig, nc *config.Config) {
5766
c.Headers = nc.API.HTTPHeaders
5867
}
5968

69+
func addCORSDefaults(c *cmdsHttp.ServerConfig) {
70+
// by default use localhost origins
71+
if len(c.CORSOpts.AllowedOrigins) == 0 {
72+
c.CORSOpts.AllowedOrigins = defaultLocalhostOrigins
73+
}
74+
75+
// by default, use GET, PUT, POST
76+
if len(c.CORSOpts.AllowedMethods) == 0 {
77+
c.CORSOpts.AllowedMethods = []string{"GET", "POST", "PUT"}
78+
}
79+
}
80+
81+
func patchCORSVars(c *cmdsHttp.ServerConfig, addr net.Addr) {
82+
83+
// we have to grab the port from an addr, which may be an ip6 addr.
84+
// TODO: this should take multiaddrs and derive port from there.
85+
port := ""
86+
if tcpaddr, ok := addr.(*net.TCPAddr); ok {
87+
port = strconv.Itoa(tcpaddr.Port)
88+
} else if udpaddr, ok := addr.(*net.UDPAddr); ok {
89+
port = strconv.Itoa(udpaddr.Port)
90+
}
91+
92+
// we're listening on tcp/udp with ports. ("udp!?" you say? yeah... it happens...)
93+
for i, o := range c.CORSOpts.AllowedOrigins {
94+
// TODO: allow replacing <host>. tricky, ip4 and ip6 and hostnames...
95+
if port != "" {
96+
o = strings.Replace(o, "<port>", port, -1)
97+
}
98+
c.CORSOpts.AllowedOrigins[i] = o
99+
}
100+
}
101+
60102
func CommandsOption(cctx commands.Context) ServeOption {
61-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
103+
return func(n *core.IpfsNode, l net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
62104

63105
cfg := &cmdsHttp.ServerConfig{
64106
CORSOpts: &cors.Options{
@@ -68,6 +110,8 @@ func CommandsOption(cctx commands.Context) ServeOption {
68110

69111
addHeadersFromConfig(cfg, n.Repo.Config())
70112
addCORSFromEnv(cfg)
113+
addCORSDefaults(cfg)
114+
patchCORSVars(cfg, l.Addr())
71115

72116
cmdHandler := cmdsHttp.NewHandler(cctx, corecommands.Root, cfg)
73117
mux.Handle(cmdsHttp.ApiPath+"/", cmdHandler)

‎core/corehttp/corehttp.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ var log = eventlog.Logger("core/server")
2323
// It returns the mux to expose to future options, which may be a new mux if it
2424
// is interested in mediating requests to future options, or the same mux
2525
// initially passed in if not.
26-
type ServeOption func(*core.IpfsNode, *http.ServeMux) (*http.ServeMux, error)
26+
type ServeOption func(*core.IpfsNode, net.Listener, *http.ServeMux) (*http.ServeMux, error)
2727

2828
// makeHandler turns a list of ServeOptions into a http.Handler that implements
2929
// all of the given options, in order.
30-
func makeHandler(n *core.IpfsNode, options ...ServeOption) (http.Handler, error) {
30+
func makeHandler(n *core.IpfsNode, l net.Listener, options ...ServeOption) (http.Handler, error) {
3131
topMux := http.NewServeMux()
3232
mux := topMux
3333
for _, option := range options {
3434
var err error
35-
mux, err = option(n, mux)
35+
mux, err = option(n, l, mux)
3636
if err != nil {
3737
return nil, err
3838
}
@@ -65,7 +65,7 @@ func ListenAndServe(n *core.IpfsNode, listeningMultiAddr string, options ...Serv
6565
}
6666

6767
func Serve(node *core.IpfsNode, lis net.Listener, options ...ServeOption) error {
68-
handler, err := makeHandler(node, options...)
68+
handler, err := makeHandler(node, lis, options...)
6969
if err != nil {
7070
return err
7171
}

‎core/corehttp/gateway.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package corehttp
22

33
import (
44
"fmt"
5+
"net"
56
"net/http"
67
"sync"
78

@@ -27,7 +28,7 @@ func NewGateway(conf GatewayConfig) *Gateway {
2728
}
2829

2930
func (g *Gateway) ServeOption() ServeOption {
30-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
31+
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
3132
// pass user's HTTP headers
3233
g.Config.Headers = n.Repo.Config().Gateway.HTTPHeaders
3334

@@ -50,7 +51,7 @@ func GatewayOption(writable bool) ServeOption {
5051
}
5152

5253
func VersionOption() ServeOption {
53-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
54+
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
5455
mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
5556
fmt.Fprintf(w, "Client Version: %s\n", id.ClientVersion)
5657
fmt.Fprintf(w, "Protocol Version: %s\n", id.IpfsVersion)

‎core/corehttp/gateway_test.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ func newNodeWithMockNamesys(t *testing.T, ns mockNamesys) *core.IpfsNode {
5555
return n
5656
}
5757

58+
type delegatedHandler struct {
59+
http.Handler
60+
}
61+
62+
func (dh *delegatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
63+
dh.Handler.ServeHTTP(w, r)
64+
}
65+
5866
func TestGatewayGet(t *testing.T) {
5967
t.Skip("not sure whats going on here")
6068
ns := mockNamesys{}
@@ -65,17 +73,21 @@ func TestGatewayGet(t *testing.T) {
6573
}
6674
ns["example.com"] = path.FromString("/ipfs/" + k)
6775

68-
h, err := makeHandler(n,
76+
// need this variable here since we need to construct handler with
77+
// listener, and server with handler. yay cycles.
78+
dh := &delegatedHandler{}
79+
ts := httptest.NewServer(dh)
80+
defer ts.Close()
81+
82+
dh.Handler, err = makeHandler(n,
83+
ts.Listener,
6984
IPNSHostnameOption(),
7085
GatewayOption(false),
7186
)
7287
if err != nil {
7388
t.Fatal(err)
7489
}
7590

76-
ts := httptest.NewServer(h)
77-
defer ts.Close()
78-
7991
t.Log(ts.URL)
8092
for _, test := range []struct {
8193
host string

‎core/corehttp/ipns_hostname.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package corehttp
22

33
import (
4+
"net"
45
"net/http"
56
"strings"
67

@@ -13,7 +14,7 @@ import (
1314
// an IPNS name.
1415
// The rewritten request points at the resolved name on the gateway handler.
1516
func IPNSHostnameOption() ServeOption {
16-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
17+
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
1718
childMux := http.NewServeMux()
1819
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
1920
ctx, cancel := context.WithCancel(n.Context())

‎core/corehttp/logs.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package corehttp
22

33
import (
44
"io"
5+
"net"
56
"net/http"
67

78
core "github.com/ipfs/go-ipfs/core"
@@ -36,7 +37,7 @@ func (w *writeErrNotifier) Write(b []byte) (int, error) {
3637
}
3738

3839
func LogOption() ServeOption {
39-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
40+
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
4041
mux.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) {
4142
w.WriteHeader(200)
4243
wnf, errs := newWriteErrNotifier(w)

‎core/corehttp/prometheus.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package corehttp
22

33
import (
4+
"net"
45
"net/http"
56

67
prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
@@ -9,7 +10,7 @@ import (
910
)
1011

1112
func PrometheusOption(path string) ServeOption {
12-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
13+
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
1314
mux.Handle(path, prom.Handler())
1415
return mux, nil
1516
}

‎core/corehttp/redirect.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package corehttp
22

33
import (
4+
"net"
45
"net/http"
56

67
core "github.com/ipfs/go-ipfs/core"
78
)
89

910
func RedirectOption(path string, redirect string) ServeOption {
1011
handler := &redirectHandler{redirect}
11-
return func(n *core.IpfsNode, mux *http.ServeMux) (*http.ServeMux, error) {
12+
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
1213
mux.Handle("/"+path+"/", handler)
1314
return mux, nil
1415
}

0 commit comments

Comments
 (0)
Please sign in to comment.