Skip to content

Commit

Permalink
Merge pull request #7 from SiaFoundation/nate/more-fetch-settings
Browse files Browse the repository at this point in the history
Add remote fetch allowlist
  • Loading branch information
n8maninger authored Nov 21, 2023
2 parents 2d7de98 + 71c4834 commit 43a7a25
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 8 deletions.
19 changes: 16 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package config

import "github.com/ipfs/go-cid"

type (
// Renterd contains the address, password, and bucket on the renterd worker
Renterd struct {
Expand All @@ -8,18 +10,29 @@ type (
Bucket string `yaml:"bucket"`
}

// RemoteFetch contains settings for enabling/disabling remote IPFS block
// fetching.
RemoteFetch struct {
// Enabled indicates whether remote IPFS block fetching is enabled.
// If false, all served IPFS blocks must be pinned locally.
Enabled bool `yaml:"enabled"`
// Allowlist contains the CIDs of blocks that are allowed to be
// fetched remotely. If empty, all blocks are allowed.
AllowList []cid.Cid `yaml:"allowlist"`
}

// HTTPGateway contains the configuration for the IPFS HTTP gateway
HTTPGateway struct {
ListenAddress string `yaml:"ListenAddress"`
RedirectPathStyle bool `yaml:"redirectPathStyle"`
ListenAddress string `yaml:"ListenAddress"`
RedirectPathStyle bool `yaml:"redirectPathStyle"`
Fetch RemoteFetch `yaml:"fetch"`
}

// IPFS contains the configuration for the IPFS node
IPFS struct {
PrivateKey string `yaml:"privateKey"`
ListenAddresses []string `yaml:"listenAddresses"`
AnnounceAddresses []string `yaml:"announceAddresses"`
FetchRemote bool `yaml:"fetchRemote"`
Gateway HTTPGateway `yaml:"gateway"`
}

Expand Down
28 changes: 23 additions & 5 deletions http/ipfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ func getURLCID(r *http.Request) (c cid.Cid, path []string, redirect bool, _ erro
return cid, strings.Split(r.URL.Path, "/")[1:], false, nil
}

path = strings.Split(strings.Trim(r.URL.Path, "/"), "/")
// check if the path contains a CID
if strings.HasPrefix(r.URL.Path, "/ipfs/") || strings.HasPrefix(r.URL.Path, "/ipns/") {
pathPart := strings.Split(r.URL.Path, "/")
cidStr, path = pathPart[2], pathPart[3:]
if len(path) >= 2 && path[0] == "ipfs" || path[0] == "ipns" {
cidStr, path = path[1], path[2:]

if c, err := cid.Parse(cidStr); err == nil {
return c, path, true, nil
Expand Down Expand Up @@ -73,6 +73,22 @@ func redirectPathCID(w http.ResponseWriter, r *http.Request, c cid.Cid, path []s
http.Redirect(w, r, u.String(), http.StatusMovedPermanently)
}

func (is *ipfsGatewayServer) allowRemoteFetch(c cid.Cid) bool {
if !is.config.IPFS.Gateway.Fetch.Enabled {
return false // deny all
} else if len(is.config.IPFS.Gateway.Fetch.AllowList) == 0 {
return true // allow all
}

// allowlist check
for _, match := range is.config.IPFS.Gateway.Fetch.AllowList {
if c.Equals(match) {
return true
}
}
return false
}

func (is *ipfsGatewayServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

Expand All @@ -97,17 +113,19 @@ func (is *ipfsGatewayServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {

// TODO: support paths in Sia proxied downloads
err = is.sia.ProxyHTTPDownload(c, r, w)
if errors.Is(err, sia.ErrNotFound) && is.config.IPFS.FetchRemote {
if errors.Is(err, sia.ErrNotFound) && is.allowRemoteFetch(c) {
is.log.Info("downloading from ipfs", zap.Stringer("cid", c))
r, err := is.ipfs.DownloadCID(ctx, c, path)
if err != nil {
http.Error(w, "", http.StatusInternalServerError)
http.Error(w, "", http.StatusNotFound)
is.log.Error("failed to download cid", zap.Error(err))
return
}
defer r.Close()

io.Copy(w, r)
} else if errors.Is(err, sia.ErrNotFound) {
http.Error(w, "", http.StatusNotFound)
} else if err != nil {
http.Error(w, "", http.StatusInternalServerError)
is.log.Error("failed to get block", zap.Error(err))
Expand Down

0 comments on commit 43a7a25

Please sign in to comment.