From aad86e08a31a11ecd6660a421c07ba1cdb5b7921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Wed, 10 Dec 2025 15:42:06 +0100 Subject: [PATCH] Refactor filevalidation.FileValidator constructor with options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Émile Ré --- .../trustCenter/TrustCenterFilesTab.tsx | 12 ++++ pkg/filevalidation/validator.go | 62 ++++++++++------ pkg/filevalidation/validator_test.go | 18 ++--- pkg/probo/service.go | 72 +++++++------------ 4 files changed, 89 insertions(+), 75 deletions(-) diff --git a/apps/console/src/pages/organizations/trustCenter/TrustCenterFilesTab.tsx b/apps/console/src/pages/organizations/trustCenter/TrustCenterFilesTab.tsx index 38948fd6a..1c0234ff4 100644 --- a/apps/console/src/pages/organizations/trustCenter/TrustCenterFilesTab.tsx +++ b/apps/console/src/pages/organizations/trustCenter/TrustCenterFilesTab.tsx @@ -39,20 +39,32 @@ type ContextType = { }; const acceptedFileTypes = { + "application/csv": [".csv"], "application/json": [".json"], "application/msword": [".doc"], "application/pdf": [".pdf"], "application/vnd.ms-excel": [".xls"], "application/vnd.ms-powerpoint": [".ppt"], + "application/vnd.oasis.opendocument.presentation": [".odp"], + "application/vnd.oasis.opendocument.spreadsheet": [".ods"], + "application/vnd.oasis.opendocument.text": [".odt"], "application/vnd.openxmlformats-officedocument.presentationml.presentation": [".pptx"], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [".xlsx"], "application/vnd.openxmlformats-officedocument.wordprocessingml.document": [".docx"], + "application/yaml": [".yaml", ".yml"], + "image/gif": [".gif"], "image/jpeg": [".jpeg", ".jpg"], "image/png": [".png"], "image/svg+xml": [".svg"], "image/webp": [".webp"], "text/csv": [".csv"], + "text/json": [".json"], "text/markdown": [".md"], + "text/plain": [".txt"], + "text/uri-list; charset=utf-8": [".uri"], + "text/uri-list": [".uri"], + "text/x-log": [".log"], + "text/yaml": [".yaml", ".yml"], } export default function TrustCenterFilesTab() { diff --git a/pkg/filevalidation/validator.go b/pkg/filevalidation/validator.go index 478628c61..cf3936a29 100644 --- a/pkg/filevalidation/validator.go +++ b/pkg/filevalidation/validator.go @@ -105,16 +105,54 @@ type FileValidator struct { Categories []string } +type Opt func(v *FileValidator) *FileValidator + +func WithCategories(categories ...string) Opt { + return func(v *FileValidator) *FileValidator { + v.Categories = categories + + categoryMap := make(map[string]bool) + for _, category := range categories { + categoryMap[category] = true + } + + for _, fileType := range FileTypes { + if categoryMap[fileType.Category] { + v.AllowedMimeTypes[fileType.MimeType] = true + for _, ext := range fileType.Extensions { + if v.AllowedExtensions[ext] == nil { + v.AllowedExtensions[ext] = []string{} + } + v.AllowedExtensions[ext] = append(v.AllowedExtensions[ext], fileType.MimeType) + } + } + } + + return v + } +} + +func WithMaxFileSize(maxFileSize int64) Opt { + return func(v *FileValidator) *FileValidator { + v.MaxFileSize = maxFileSize + + return v + } +} + // NewValidator creates a new file validator using supported file types -func NewValidator(categories ...string) *FileValidator { +func NewValidator(opts ...Opt) *FileValidator { v := &FileValidator{ MaxFileSize: DefaultMaxFileSize, AllowedMimeTypes: make(map[string]bool), AllowedExtensions: make(map[string][]string), - Categories: categories, } - if len(categories) == 0 { + for _, opt := range opts { + v = opt(v) + } + + if len(v.Categories) == 0 { for _, fileType := range FileTypes { v.AllowedMimeTypes[fileType.MimeType] = true for _, ext := range fileType.Extensions { @@ -124,24 +162,6 @@ func NewValidator(categories ...string) *FileValidator { v.AllowedExtensions[ext] = append(v.AllowedExtensions[ext], fileType.MimeType) } } - return v - } - - categoryMap := make(map[string]bool) - for _, category := range categories { - categoryMap[category] = true - } - - for _, fileType := range FileTypes { - if categoryMap[fileType.Category] { - v.AllowedMimeTypes[fileType.MimeType] = true - for _, ext := range fileType.Extensions { - if v.AllowedExtensions[ext] == nil { - v.AllowedExtensions[ext] = []string{} - } - v.AllowedExtensions[ext] = append(v.AllowedExtensions[ext], fileType.MimeType) - } - } } return v diff --git a/pkg/filevalidation/validator_test.go b/pkg/filevalidation/validator_test.go index 45cb35825..ca1c28e73 100644 --- a/pkg/filevalidation/validator_test.go +++ b/pkg/filevalidation/validator_test.go @@ -60,7 +60,7 @@ func TestNewValidator(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - v := NewValidator(tc.categories...) + v := NewValidator(WithCategories(tc.categories...)) // Test expected mime types are allowed for _, mime := range tc.expectedMimes { @@ -123,7 +123,7 @@ func TestValidate(t *testing.T) { }{ { name: "Valid PDF file", - validator: NewValidator(CategoryDocument), + validator: NewValidator(WithCategories(CategoryDocument)), filename: "test.pdf", contentType: "application/pdf", fileSize: 1024 * 1024, // 1MB @@ -140,7 +140,7 @@ func TestValidate(t *testing.T) { }, { name: "Disallowed content type", - validator: NewValidator(CategoryDocument), + validator: NewValidator(WithCategories(CategoryDocument)), filename: "test.jpg", contentType: "image/jpeg", fileSize: 1024 * 1024, @@ -158,7 +158,7 @@ func TestValidate(t *testing.T) { }, { name: "Disallowed file extension", - validator: NewValidator(CategoryDocument), + validator: NewValidator(WithCategories(CategoryDocument)), filename: "test.exe", contentType: "application/octet-stream", fileSize: 1024, @@ -176,7 +176,7 @@ func TestValidate(t *testing.T) { }, { name: "Valid image file", - validator: NewValidator(CategoryImage), + validator: NewValidator(WithCategories(CategoryImage)), filename: "test.jpg", contentType: "image/jpeg", fileSize: 1024 * 1024, @@ -184,7 +184,7 @@ func TestValidate(t *testing.T) { }, { name: "Valid with multiple categories", - validator: NewValidator(CategoryImage, CategoryDocument), + validator: NewValidator(WithCategories(CategoryImage, CategoryDocument)), filename: "test.jpg", contentType: "image/jpeg", fileSize: 1024 * 1024, @@ -315,7 +315,7 @@ func TestFileCategories(t *testing.T) { for _, tc := range categoryTests { t.Run(tc.category, func(t *testing.T) { - v := NewValidator(tc.category) + v := NewValidator(WithCategories(tc.category)) // Test that the validator accepts files of this category err := v.Validate("test"+tc.validExt, tc.validMimeType, 1024) @@ -381,7 +381,7 @@ func TestMultipleExtensionsPerMimeType(t *testing.T) { // Test MIME types that have multiple allowed extensions for _, fileType := range FileTypes { if len(fileType.Extensions) > 1 { - v := NewValidator(fileType.Category) + v := NewValidator(WithCategories(fileType.Category)) // All extensions for this MIME type should be valid for _, ext := range fileType.Extensions { @@ -434,7 +434,7 @@ func BenchmarkValidate(b *testing.B) { // BenchmarkNewValidator benchmarks the NewValidator function func BenchmarkNewValidator(b *testing.B) { for i := 0; i < b.N; i++ { - _ = NewValidator(CategoryDocument, CategoryImage) + _ = NewValidator(WithCategories(CategoryDocument, CategoryImage)) } } diff --git a/pkg/probo/service.go b/pkg/probo/service.go index f06bc02e2..28bc68371 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -180,13 +180,15 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.Evidences = &EvidenceService{ svc: tenantService, fileValidator: filevalidation.NewValidator( - filevalidation.CategoryDocument, - filevalidation.CategorySpreadsheet, - filevalidation.CategoryPresentation, - filevalidation.CategoryData, - filevalidation.CategoryText, - filevalidation.CategoryImage, - filevalidation.CategoryVideo, + filevalidation.WithCategories( + filevalidation.CategoryDocument, + filevalidation.CategorySpreadsheet, + filevalidation.CategoryPresentation, + filevalidation.CategoryData, + filevalidation.CategoryText, + filevalidation.CategoryImage, + filevalidation.CategoryVideo, + ), ), } tenantService.Peoples = &PeopleService{svc: tenantService} @@ -198,12 +200,17 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.Organizations = &OrganizationService{ svc: tenantService, fileValidator: filevalidation.NewValidator( - filevalidation.CategoryImage, + filevalidation.WithCategories(filevalidation.CategoryImage), ), } tenantService.Controls = &ControlService{svc: tenantService} tenantService.Risks = &RiskService{svc: tenantService} - tenantService.VendorComplianceReports = &VendorComplianceReportService{svc: tenantService, fileValidator: filevalidation.NewValidator(filevalidation.CategoryDocument)} + tenantService.VendorComplianceReports = &VendorComplianceReportService{ + svc: tenantService, + fileValidator: filevalidation.NewValidator( + filevalidation.WithCategories(filevalidation.CategoryDocument), + ), + } tenantService.VendorBusinessAssociateAgreements = &VendorBusinessAssociateAgreementService{svc: tenantService} tenantService.VendorContacts = &VendorContactService{svc: tenantService} tenantService.VendorDataPrivacyAgreements = &VendorDataPrivacyAgreementService{svc: tenantService} @@ -219,42 +226,17 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.TrustCenterReferences = &TrustCenterReferenceService{svc: tenantService} tenantService.TrustCenterFiles = &TrustCenterFileService{ svc: tenantService, - fileValidator: &filevalidation.FileValidator{ - MaxFileSize: 10 * 1024 * 1024, // 10MB - AllowedMimeTypes: map[string]bool{ - "application/json": true, - "application/msword": true, - "application/pdf": true, - "application/vnd.ms-excel": true, - "application/vnd.ms-powerpoint": true, - "application/vnd.openxmlformats-officedocument.presentationml.presentation": true, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": true, - "application/vnd.openxmlformats-officedocument.wordprocessingml.document": true, - "image/jpeg": true, - "image/png": true, - "image/svg+xml": true, - "image/webp": true, - "text/csv": true, - "text/markdown": true, - }, - AllowedExtensions: map[string][]string{ - ".csv": {"text/csv"}, - ".doc": {"application/msword"}, - ".docx": {"application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, - ".jpeg": {"image/jpeg"}, - ".jpg": {"image/jpeg"}, - ".json": {"application/json"}, - ".md": {"text/markdown"}, - ".pdf": {"application/pdf"}, - ".png": {"image/png"}, - ".ppt": {"application/vnd.ms-powerpoint"}, - ".pptx": {"application/vnd.openxmlformats-officedocument.presentationml.presentation"}, - ".svg": {"image/svg+xml"}, - ".webp": {"image/webp"}, - ".xls": {"application/vnd.ms-excel"}, - ".xlsx": {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, - }, - }, + fileValidator: filevalidation.NewValidator( + filevalidation.WithCategories( + filevalidation.CategoryData, + filevalidation.CategoryDocument, + filevalidation.CategoryImage, + filevalidation.CategoryPresentation, + filevalidation.CategorySpreadsheet, + filevalidation.CategoryText, + ), + filevalidation.WithMaxFileSize(10*1024*1024), // 10MB + ), } tenantService.Nonconformities = &NonconformityService{svc: tenantService} tenantService.Obligations = &ObligationService{svc: tenantService}