~emersion/soju-dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[PATCH] Add CORS headers in fileUploadHandler

Details
Message ID
<20240209125521.14685-1-amk@amk.ie>
DKIM signature
pass
Download raw message
Patch: +66 -6
---
 cmd/soju/main.go         |  7 +++--
 fileupload/fileupload.go | 65 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/cmd/soju/main.go b/cmd/soju/main.go
index 7dfed44..04de78b 100644
--- a/cmd/soju/main.go
+++ b/cmd/soju/main.go
@@ -159,9 +159,10 @@ func main() {
	fileUploadHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cfg := srv.Config()
		h := fileupload.Handler{
			Uploader: cfg.FileUploader,
			DB:       db,
			Auth:     cfg.Auth,
			Uploader:    cfg.FileUploader,
			DB:          db,
			Auth:        cfg.Auth,
			HTTPOrigins: cfg.HTTPOrigins,
		}
		h.ServeHTTP(w, r)
	})
diff --git a/fileupload/fileupload.go b/fileupload/fileupload.go
index cceb4a5..bcce205 100644
--- a/fileupload/fileupload.go
+++ b/fileupload/fileupload.go
@@ -3,11 +3,14 @@ package fileupload
import (
	"crypto/rand"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"mime"
	"net/http"
	"net/url"
	"path"
	"path/filepath"
	"strings"
	"time"

@@ -53,14 +56,70 @@ func New(driver, source string) (Uploader, error) {
}

type Handler struct {
	Uploader Uploader
	Auth     auth.Authenticator
	DB       database.Database
	Uploader    Uploader
	Auth        auth.Authenticator
	DB          database.Database
	HTTPOrigins []string
}

func (h *Handler) handleCors(resp http.ResponseWriter, req *http.Request) error {
	resp.Header().Add("Access-Control-Allow-Credentials", "true")
	resp.Header().Add("Access-Control-Allow-Headers", "authorization,content-type")

	if len(h.HTTPOrigins) == 0 {
		return nil
	}

	reqOrigin := req.Header.Get("Origin")
	if reqOrigin == "" {
		return nil
	}
	u, err := url.Parse(reqOrigin)
	if err != nil {
		http.Error(resp, "Unauthorized", http.StatusUnauthorized)
		return fmt.Errorf("invald Origin header: %w", err)
	}
	if u.Host == req.Host {
		resp.Header().Add("Access-Control-Allow-Origin", reqOrigin)
		return nil
	}

	for _, origin := range h.HTTPOrigins {
		if origin == "*" {
			resp.Header().Add("Access-Control-Allow-Origin", reqOrigin)
			resp.Header().Add("Vary", "Origin")
			return nil
		}

		if strings.EqualFold(origin, reqOrigin) {
			resp.Header().Add("Access-Control-Allow-Origin", origin)
			return nil
		}

		match, err := filepath.Match(origin, reqOrigin)
		if err != nil {
			http.Error(resp, "Internal error", http.StatusInternalServerError)
			return err
		}
		if match {
			resp.Header().Add("Access-Control-Allow-Origin", reqOrigin)
			resp.Header().Add("Vary", "Origin")
			return nil
		}
	}

	http.Error(resp, "Unauthorized Origin", http.StatusUnauthorized)

	return errors.New("unauthorized origin")
}

func (h *Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	resp.Header().Set("Content-Security-Policy", "sandbox; default-src 'none'; script-src 'none';")

	if err := h.handleCors(resp, req); err != nil {
		return
	}

	if h.Uploader == nil {
		http.NotFound(resp, req)
		return
-- 
2.43.0
Reply to thread Export thread (mbox)