Skip to content

Commit

Permalink
Allow block lists (#63)
Browse files Browse the repository at this point in the history
* Add block and allow lists to config

* Add allow and block lists handling to subdomain middleware

* Fix missing return after handler.ServerHTTP in SubdomainMiddleware

* Remove api/ from excluded directories of golangci and fix raised lint errors
  • Loading branch information
thomas-senechal authored Aug 5, 2024
1 parent e3cee15 commit 9de00c5
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 26 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ linters:

issues:
exclude-dirs:
- api/

linters-settings:
wsl:
Expand Down
1 change: 1 addition & 0 deletions api/read/restapi/configure_de_web.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func configureAPI(api *operations.DeWebAPI) http.Handler {
return middleware.NotImplemented("operation operations.DefaultPage has not yet been implemented")
})
}

if api.GetResourceHandler == nil {
api.GetResourceHandler = operations.GetResourceHandlerFunc(func(params operations.GetResourceParams) middleware.Responder {
return middleware.NotImplemented("operation operations.GetResource has not yet been implemented")
Expand Down
16 changes: 13 additions & 3 deletions int/api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ const (
)

type yamlServerConfig struct {
Domain string `yaml:"domain"`
NetworkNodeURL string `yaml:"network_node_url"`
APIPort int `yaml:"api_port"`
Domain string `yaml:"domain"`
NetworkNodeURL string `yaml:"network_node_url"`
APIPort int `yaml:"api_port"`
AllowList []string `yaml:"allow_list"`
BlockList []string `yaml:"block_list"`
}

type ServerConfig struct {
Domain string
APIPort int
NetworkInfos msConfig.NetworkInfos
AllowList []string
BlockList []string
}

func DefaultConfig() *ServerConfig {
Expand All @@ -35,6 +39,8 @@ func DefaultConfig() *ServerConfig {
Domain: DefaultDomain,
APIPort: DefaultAPIPort,
NetworkInfos: nodeConf.NetworkInfos,
AllowList: []string{},
BlockList: []string{},
}
}

Expand Down Expand Up @@ -64,9 +70,11 @@ func LoadServerConfig(configPath string) (*ServerConfig, error) {
if yamlConf.Domain == "" {
yamlConf.Domain = DefaultDomain
}

if yamlConf.NetworkNodeURL == "" {
yamlConf.NetworkNodeURL = DefaultNetworkNodeURL
}

if yamlConf.APIPort == 0 {
yamlConf.APIPort = DefaultAPIPort
}
Expand All @@ -77,5 +85,7 @@ func LoadServerConfig(configPath string) (*ServerConfig, error) {
Domain: yamlConf.Domain,
APIPort: yamlConf.APIPort,
NetworkInfos: nodeConf.NetworkInfos,
AllowList: yamlConf.AllowList,
BlockList: yamlConf.BlockList,
}, nil
}
75 changes: 53 additions & 22 deletions int/api/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"fmt"
"net/http"
"slices"
"strings"

"github.com/massalabs/DeWeb/int/api/config"
Expand All @@ -19,41 +20,54 @@ func SubdomainMiddleware(handler http.Handler, conf *config.ServerConfig) http.H
logger.Debugf("SubdomainMiddleware: Handling request for %s", r.Host)

subdomain := extractSubdomain(r.Host, conf.Domain)
if subdomain != "" {
path := cleanPath(r.URL.Path)
if subdomain == "" {
logger.Debug("SubdomainMiddleware: No subdomain found. Proceeding with the next handler.")
handler.ServeHTTP(w, r)

logger.Debugf("SubdomainMiddleware: Subdomain %s found, resolving address", subdomain)
return
}

address, err := resolveAddress(subdomain, conf.NetworkInfos)
if err != nil {
handleResolveError(w, subdomain, path, err)
return
}
path := cleanPath(r.URL.Path)

content, mimeType, err := getWebsiteResource(&conf.NetworkInfos, address, path)
if err != nil {
logger.Errorf("Failed to get website %s resource %s: %v", address, path, err)
http.Error(w, err.Error(), http.StatusInternalServerError)
logger.Debugf("SubdomainMiddleware: Subdomain %s found, resolving address", subdomain)

return
}
address, err := resolveAddress(subdomain, conf.NetworkInfos)
if err != nil {
handleResolveError(w, subdomain, path, err)

w.Header().Set("Content-Type", mimeType)
return
}

_, err = w.Write(content)
if err != nil {
logger.Errorf("Failed to write content: %v", err)
http.Error(w, "an error occurred while writing response", http.StatusInternalServerError)
}
if !isWebsiteAllowed(address, subdomain, conf.AllowList, conf.BlockList) {
logger.Warnf("Subdomain %s or address %s is not allowed", subdomain, address)
http.Error(w, "Subdomain is not accessible from this DeWeb instance", http.StatusForbidden)

return
}

logger.Debug("SubdomainMiddleware: No subdomain found. Proceeding with the next handler.")
handler.ServeHTTP(w, r)
serveContent(conf, address, path, w)
})
}

// serveContent serves the requested resource for the given website address.
func serveContent(conf *config.ServerConfig, address string, path string, w http.ResponseWriter) {
content, mimeType, err := getWebsiteResource(&conf.NetworkInfos, address, path)
if err != nil {
logger.Errorf("Failed to get website %s resource %s: %v", address, path, err)
http.Error(w, err.Error(), http.StatusInternalServerError)

return
}

w.Header().Set("Content-Type", mimeType)

_, err = w.Write(content)
if err != nil {
logger.Errorf("Failed to write content: %v", err)
http.Error(w, "an error occurred while writing response", http.StatusInternalServerError)
}
}

// extractSubdomain extracts the subdomain from the host.
func extractSubdomain(host string, domain string) string {
subdomain := strings.Split(host, domain)[0]
Expand Down Expand Up @@ -139,3 +153,20 @@ func getWebsiteResource(network *msConfig.NetworkInfos, websiteAddress, resource

return content, contentType, nil
}

// isWebsiteAllowed checks the allow and block lists and returns false if the address or domain is not allowed.
// If the allow list is empty, all addresses and domains are allowed, except those in the block list.
// Otherwise, only addresses and domains in the allow list are allowed.
func isWebsiteAllowed(address string, domain string, allowList, blockList []string) bool {
if slices.Contains(blockList, address) || slices.Contains(blockList, domain) {
logger.Debugf("Address %s or domain %s is in the block list", address, domain)
return false
}

if len(allowList) > 0 && !slices.Contains(allowList, address) && !slices.Contains(allowList, domain) {
logger.Debugf("Address %s or domain %s is not in the allow list", address, domain)
return false
}

return true
}

0 comments on commit 9de00c5

Please sign in to comment.