fix(datasets): accept BigTIFF headers and sanitise object keys

F1: ValidateFileContent rejected the pipeline's own output. GDAL writes a
BigTIFF header ("II+\0" / "MM\0+") whenever BIGTIFF=IF_SAFER kicks in for a
large raster, so accept both alongside the classic TIFF magic and reword the
error to "file is not a valid TIFF/BigTIFF GeoTIFF". GodalIO.Create now
delegates to an unexported createGTiff so a test can force BIGTIFF=YES and
assert the produced header passes the check.

F3: a user-supplied filename went straight into the S3 object key for dataset
uploads and for both dataset and dataset-group SLD uploads, so "../../x.sld"
escaped the dataset's own prefix. Reduce every such name to its base with a
shared safeObjectName helper, rejecting names with no usable base.

F9: rename the shadowing inner "raw" in the PATCH dg_id case to "s".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 14:44:21 +05:00
parent 6aec00ee29
commit bcda76003c
9 changed files with 215 additions and 13 deletions

View File

@@ -255,3 +255,29 @@ func TestDatasetGroupService_Update_RequiresSlug(t *testing.T) {
t.Fatalf("want ErrValidation, got %v", err)
}
}
func TestDatasetGroupService_UploadSLD_RejectsPathTraversal(t *testing.T) {
ctx := context.Background()
groups := newStubGroupRepo()
store := newStubStore()
svc := NewDatasetGroupService(groups, newStubDatasetRepo(), store)
g, err := svc.Create(ctx, DatasetGroupInput{Code: "pop", Name: "Population"})
if err != nil {
t.Fatal(err)
}
updated, err := svc.UploadSLD(ctx, g.ID, UploadSLDInput{
Filename: "../../other/sld/evil.sld", ContentType: "application/xml", Size: 3, Reader: strings.NewReader("<x>"),
})
if err != nil {
t.Fatal(err)
}
wantPrefix := "groups/" + g.ID.String() + "/sld/"
if updated.SldStorageKey == nil || !strings.HasPrefix(*updated.SldStorageKey, wantPrefix) ||
!strings.HasSuffix(*updated.SldStorageKey, "evil.sld") {
t.Fatalf("sld key escaped the group prefix: %v", updated.SldStorageKey)
}
if len(store.put) != 1 || !strings.HasPrefix(store.put[0], wantPrefix) {
t.Fatalf("object stored outside the group sld prefix: %v", store.put)
}
}