diff options
Diffstat (limited to '')
-rw-r--r-- | packages/soju-upload.patch | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/packages/soju-upload.patch b/packages/soju-upload.patch new file mode 100644 index 0000000..03efe76 --- /dev/null +++ b/packages/soju-upload.patch @@ -0,0 +1,222 @@ +diff --git i/fileupload/fileupload.go w/fileupload/fileupload.go +index 07fccf1..55104f8 100644 +--- i/fileupload/fileupload.go ++++ w/fileupload/fileupload.go +@@ -7,6 +7,7 @@ import ( + "errors" + "fmt" + "io" ++ "log" + "mime" + "net/http" + "net/url" +@@ -153,30 +154,35 @@ func (h *Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + return + } + ++ var err error + switch req.Method { + case http.MethodOptions: + resp.WriteHeader(http.StatusNoContent) + case http.MethodHead, http.MethodGet: +- h.fetch(resp, req) ++ err = h.fetch(resp, req) + case http.MethodPost: +- h.store(resp, req) ++ err = h.store(resp, req) + default: + http.Error(resp, "only OPTIONS, HEAD, GET and POST are allowed", http.StatusMethodNotAllowed) ++ err = errors.New(http.StatusText(http.StatusMethodNotAllowed)) ++ } ++ if err != nil { ++ log.Printf("upload: %s", err.Error()) + } + } + +-func (h *Handler) fetch(resp http.ResponseWriter, req *http.Request) { ++func (h *Handler) fetch(resp http.ResponseWriter, req *http.Request) error { + prefix := "/uploads/" + if !strings.HasPrefix(req.URL.Path, prefix) { + http.Error(resp, "invalid path", http.StatusNotFound) +- return ++ return fmt.Errorf("invalid path") + } + + filename := strings.TrimPrefix(req.URL.Path, prefix) + filename = path.Join("/", filename)[1:] // prevent directory traversal + if filename == "" { + http.Error(resp, "invalid path", http.StatusNotFound) +- return ++ return fmt.Errorf("invalid path") + } + + basename, modTime, content, err := h.Uploader.load(req.Context(), filename) +@@ -184,10 +190,10 @@ func (h *Handler) fetch(resp http.ResponseWriter, req *http.Request) { + var httpErr *httpError + if errors.As(err, &httpErr) { + httpErr.Write(resp) +- return ++ return err + } + http.Error(resp, "failed to open file", http.StatusNotFound) +- return ++ return fmt.Errorf("failed to open file: %v", err) + } + defer content.Close() + +@@ -200,7 +206,7 @@ func (h *Handler) fetch(resp http.ResponseWriter, req *http.Request) { + _, err := content.Seek(0, io.SeekStart) // rewind to output whole file + if err != nil { + http.Error(resp, "failed to seek file", http.StatusInternalServerError) +- return ++ return fmt.Errorf("failed to seek file: %v", err) + } + } + +@@ -219,18 +225,20 @@ func (h *Handler) fetch(resp http.ResponseWriter, req *http.Request) { + resp.Header().Set("Content-Disposition", contentDisp) + + http.ServeContent(resp, req, basename, modTime, content) ++ ++ return nil + } + +-func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { ++func (h *Handler) store(resp http.ResponseWriter, req *http.Request) error { + if req.URL.Path != "/uploads" { + http.Error(resp, "invalid path", http.StatusNotFound) +- return ++ return fmt.Errorf("invalid path") + } + + authz := req.Header.Get("Authorization") + if authz == "" { + http.Error(resp, "missing Authorization header", http.StatusUnauthorized) +- return ++ return fmt.Errorf("missing Authorization header") + } + + var ( +@@ -243,26 +251,26 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + plainAuth := h.Auth.Plain + if plainAuth == nil { + http.Error(resp, "Basic scheme in Authorization header not supported", http.StatusBadRequest) +- return ++ return fmt.Errorf("Basic scheme in Authorization header not supported") + } + var password string + var ok bool + username, password, ok = req.BasicAuth() + if !ok { + http.Error(resp, "invalid Authorization header", http.StatusBadRequest) +- return ++ return fmt.Errorf("invalid Authorization header") + } + err = plainAuth.AuthPlain(req.Context(), h.DB, username, password) + case "bearer": + oauthAuth := h.Auth.OAuthBearer + if oauthAuth == nil { + http.Error(resp, "Bearer scheme in Authorization header not supported", http.StatusBadRequest) +- return ++ return fmt.Errorf("Bearer scheme in Authorization header not supported") + } + username, err = oauthAuth.AuthOAuthBearer(req.Context(), h.DB, param) + default: + http.Error(resp, "unsupported Authorization header scheme", http.StatusBadRequest) +- return ++ return fmt.Errorf("unsupported Authorization header scheme") + } + if err != nil { + var msg string +@@ -272,7 +280,7 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + msg = "authentication failed" + } + http.Error(resp, msg, http.StatusForbidden) +- return ++ return fmt.Errorf("%s: %v", msg, err) + } + + var mimeType string +@@ -284,7 +292,7 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + mimeType, params, err = mime.ParseMediaType(contentType) + if err != nil { + http.Error(resp, "failed to parse Content-Type", http.StatusBadRequest) +- return ++ return fmt.Errorf("failed to parse Content-Type: %v", err) + } + if mimeType == "application/octet-stream" { + mimeType = "" +@@ -295,7 +303,7 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + // OK + default: + http.Error(resp, "unsupported charset", http.StatusUnsupportedMediaType) +- return ++ return fmt.Errorf("unsupported charset") + } + } + +@@ -304,7 +312,7 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + _, params, err := mime.ParseMediaType(contentDisp) + if err != nil { + http.Error(resp, "failed to parse Content-Disposition", http.StatusBadRequest) +- return ++ return fmt.Errorf("failed to parse Content-Disposition: %v", err) + } + basename = path.Base(params["filename"]) + } +@@ -325,7 +333,7 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + var httpErr *httpError + if errors.As(err, &httpErr) { + httpErr.Write(resp) +- return ++ return err + } + status := http.StatusInternalServerError + var maxBytesErr *http.MaxBytesError +@@ -335,19 +343,21 @@ func (h *Handler) store(resp http.ResponseWriter, req *http.Request) { + resp.Header().Set("Upload-Limit", fmt.Sprintf("maxsize=%v", maxBytesErr.Limit)) + } + http.Error(resp, "failed to write file", status) +- return ++ return fmt.Errorf("failed to write file: %v", err) + } + + u, err := url.Parse(out) + if err != nil { + http.Error(resp, "failed to write file", http.StatusInternalServerError) +- return ++ return fmt.Errorf("failed to write file: %v", err) + } +- baseURL := url.URL{Path: "/uploads/"} ++ baseURL := url.URL{Path: "/_irc/uploads/"} + out = baseURL.ResolveReference(u).String() + + resp.Header().Set("Location", out) + resp.WriteHeader(http.StatusCreated) ++ ++ return nil + } + + func generateToken(n int) (string, error) { +diff --git i/fileupload/fs.go w/fileupload/fs.go +index c0c401d..66337a1 100644 +--- i/fileupload/fs.go ++++ w/fileupload/fs.go +@@ -56,7 +56,7 @@ func (fs *fileuploadFS) store(ctx context.Context, r io.Reader, username, mimeTy + } + + dir := filepath.Join(fs.dir, username) +- if err := os.MkdirAll(dir, 0700); err != nil { ++ if err := os.MkdirAll(dir, 0755); err != nil { + return "", fmt.Errorf("failed to create user upload directory: %w", err) + } + +@@ -77,7 +77,7 @@ func (fs *fileuploadFS) store(ctx context.Context, r io.Reader, username, mimeTy + } + basename += suffix + +- f, err = os.OpenFile(filepath.Join(dir, basename), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) ++ f, err = os.OpenFile(filepath.Join(dir, basename), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) + if err == nil { + break + } else if !os.IsExist(err) { |