All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 2m30s
- Allow the `/health` endpoint to bypass the security middleware, ensuring container health checks succeed even if the proxy IP is banned. - Add a test to verify health checks from banned IPs. - Register a HEAD route for file downloads. - Refactor admin alert status checks to use a new `isUnacknowledgedAlert` helper. - Update the security runbook documentation with clearer instructions and examples for trusted proxy configuration.
121 lines
4.0 KiB
Go
121 lines
4.0 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"warpbox/lib/boxstore"
|
|
"warpbox/lib/config"
|
|
"warpbox/lib/models"
|
|
)
|
|
|
|
const downloadTestBoxID = "abcdefabcdefabcdefabcdefabcdefab"
|
|
|
|
func TestDownloadFileServesEmbeddableMediaInlineWithRangeSupport(t *testing.T) {
|
|
app := setupDownloadFileTest(t, "clip.mp4", []byte("0123456789"))
|
|
|
|
response := performDownloadFile(app, http.MethodGet, "/box/"+downloadTestBoxID+"/files/clip.mp4", map[string]string{
|
|
"Range": "bytes=0-3",
|
|
})
|
|
|
|
if response.Code != http.StatusPartialContent {
|
|
t.Fatalf("expected ranged download to return 206, got %d", response.Code)
|
|
}
|
|
if got := response.Header().Get("Content-Disposition"); !strings.HasPrefix(got, "inline;") || !strings.Contains(got, "filename=clip.mp4") {
|
|
t.Fatalf("expected inline content disposition for embeddable media, got %q", got)
|
|
}
|
|
if got := response.Header().Get("Content-Type"); !strings.HasPrefix(got, "video/mp4") {
|
|
t.Fatalf("expected video content type, got %q", got)
|
|
}
|
|
if got := response.Header().Get("Content-Range"); got != "bytes 0-3/10" {
|
|
t.Fatalf("expected byte range header, got %q", got)
|
|
}
|
|
if got := response.Body.String(); got != "0123" {
|
|
t.Fatalf("expected ranged body, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestDownloadFileServesUnsafeInlineTypesAsAttachments(t *testing.T) {
|
|
app := setupDownloadFileTest(t, "page.html", []byte("<!doctype html><script>alert(1)</script>"))
|
|
|
|
response := performDownloadFile(app, http.MethodGet, "/box/"+downloadTestBoxID+"/files/page.html", nil)
|
|
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("expected download to return 200, got %d", response.Code)
|
|
}
|
|
if got := response.Header().Get("Content-Disposition"); !strings.HasPrefix(got, "attachment;") || !strings.Contains(got, "filename=page.html") {
|
|
t.Fatalf("expected attachment content disposition for html, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestDownloadFileSupportsHeadRequests(t *testing.T) {
|
|
app := setupDownloadFileTest(t, "clip.mp4", []byte("0123456789"))
|
|
|
|
response := performDownloadFile(app, http.MethodHead, "/box/"+downloadTestBoxID+"/files/clip.mp4", nil)
|
|
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("expected HEAD download to return 200, got %d", response.Code)
|
|
}
|
|
if got := response.Header().Get("Content-Disposition"); !strings.HasPrefix(got, "inline;") {
|
|
t.Fatalf("expected inline content disposition for HEAD request, got %q", got)
|
|
}
|
|
if response.Body.Len() != 0 {
|
|
t.Fatalf("expected HEAD response body to be empty, got %d bytes", response.Body.Len())
|
|
}
|
|
}
|
|
|
|
func setupDownloadFileTest(t *testing.T, filename string, body []byte) *App {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
restoreUploadRoot := boxstore.UploadRoot()
|
|
t.Cleanup(func() { boxstore.SetUploadRoot(restoreUploadRoot) })
|
|
boxstore.SetUploadRoot(t.TempDir())
|
|
|
|
if err := os.MkdirAll(boxstore.BoxPath(downloadTestBoxID), 0755); err != nil {
|
|
t.Fatalf("MkdirAll returned error: %v", err)
|
|
}
|
|
path, ok := boxstore.SafeBoxFilePath(downloadTestBoxID, filename)
|
|
if !ok {
|
|
t.Fatal("SafeBoxFilePath rejected test file")
|
|
}
|
|
if err := os.WriteFile(path, body, 0644); err != nil {
|
|
t.Fatalf("WriteFile returned error: %v", err)
|
|
}
|
|
|
|
manifest := models.BoxManifest{
|
|
Files: []models.BoxFile{{
|
|
ID: "0123456789abcdef",
|
|
Name: filename,
|
|
Size: int64(len(body)),
|
|
MimeType: "",
|
|
Status: models.FileStatusReady,
|
|
}},
|
|
CreatedAt: time.Now().UTC(),
|
|
}
|
|
if err := boxstore.WriteManifest(downloadTestBoxID, manifest); err != nil {
|
|
t.Fatalf("WriteManifest returned error: %v", err)
|
|
}
|
|
|
|
return &App{config: &config.Config{}}
|
|
}
|
|
|
|
func performDownloadFile(app *App, method string, path string, headers map[string]string) *httptest.ResponseRecorder {
|
|
router := gin.New()
|
|
router.GET("/box/:id/files/:filename", app.handleDownloadFile)
|
|
router.HEAD("/box/:id/files/:filename", app.handleDownloadFile)
|
|
request := httptest.NewRequest(method, path, nil)
|
|
for key, value := range headers {
|
|
request.Header.Set(key, value)
|
|
}
|
|
response := httptest.NewRecorder()
|
|
router.ServeHTTP(response, request)
|
|
return response
|
|
}
|