mirror of
https://github.com/ivuorinen/gibidify.git
synced 2026-03-06 05:58:35 +00:00
feat: update go to 1.25, add permissions and envs (#49)
* chore(ci): update go to 1.25, add permissions and envs * fix(ci): update pr-lint.yml * chore: update go, fix linting * fix: tests and linting * fix(lint): lint fixes, renovate should now pass * fix: updates, security upgrades * chore: workflow updates, lint * fix: more lint, checkmake, and other fixes * fix: more lint, convert scripts to POSIX compliant * fix: simplify codeql workflow * tests: increase test coverage, fix found issues * fix(lint): editorconfig checking, add to linters * fix(lint): shellcheck, add to linters * fix(lint): apply cr comment suggestions * fix(ci): remove step-security/harden-runner * fix(lint): remove duplication, apply cr fixes * fix(ci): tests in CI/CD pipeline * chore(lint): deduplication of strings * fix(lint): apply cr comment suggestions * fix(ci): actionlint * fix(lint): apply cr comment suggestions * chore: lint, add deps management
This commit is contained in:
@@ -1,9 +1,162 @@
|
||||
package fileproc
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxRegistryEntries is the maximum number of entries allowed in registry config slices/maps.
|
||||
MaxRegistryEntries = 1000
|
||||
// MaxExtensionLength is the maximum length for a single extension string.
|
||||
MaxExtensionLength = 100
|
||||
)
|
||||
|
||||
// RegistryConfig holds configuration for file type registry.
|
||||
// All paths must be relative without path traversal (no ".." or leading "/").
|
||||
// Extensions in CustomLanguages keys must start with "." or be alphanumeric with underscore/hyphen.
|
||||
type RegistryConfig struct {
|
||||
// CustomImages: file extensions to treat as images (e.g., ".svg", ".webp").
|
||||
// Must be relative paths without ".." or leading separators.
|
||||
CustomImages []string
|
||||
|
||||
// CustomBinary: file extensions to treat as binary (e.g., ".bin", ".dat").
|
||||
// Must be relative paths without ".." or leading separators.
|
||||
CustomBinary []string
|
||||
|
||||
// CustomLanguages: maps file extensions to language names (e.g., {".tsx": "TypeScript"}).
|
||||
// Keys must start with "." or be alphanumeric with underscore/hyphen.
|
||||
CustomLanguages map[string]string
|
||||
|
||||
// DisabledImages: image extensions to disable from default registry.
|
||||
DisabledImages []string
|
||||
|
||||
// DisabledBinary: binary extensions to disable from default registry.
|
||||
DisabledBinary []string
|
||||
|
||||
// DisabledLanguages: language extensions to disable from default registry.
|
||||
DisabledLanguages []string
|
||||
}
|
||||
|
||||
// Validate checks the RegistryConfig for invalid entries and enforces limits.
|
||||
func (c *RegistryConfig) Validate() error {
|
||||
// Validate CustomImages
|
||||
if err := validateExtensionSlice(c.CustomImages, "CustomImages"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate CustomBinary
|
||||
if err := validateExtensionSlice(c.CustomBinary, "CustomBinary"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate CustomLanguages
|
||||
if len(c.CustomLanguages) > MaxRegistryEntries {
|
||||
return fmt.Errorf(
|
||||
"CustomLanguages exceeds maximum entries (%d > %d)",
|
||||
len(c.CustomLanguages),
|
||||
MaxRegistryEntries,
|
||||
)
|
||||
}
|
||||
for ext, lang := range c.CustomLanguages {
|
||||
if err := validateExtension(ext, "CustomLanguages key"); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(lang) > MaxExtensionLength {
|
||||
return fmt.Errorf(
|
||||
"CustomLanguages value %q exceeds maximum length (%d > %d)",
|
||||
lang,
|
||||
len(lang),
|
||||
MaxExtensionLength,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate Disabled slices
|
||||
if err := validateExtensionSlice(c.DisabledImages, "DisabledImages"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateExtensionSlice(c.DisabledBinary, "DisabledBinary"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validateExtensionSlice(c.DisabledLanguages, "DisabledLanguages")
|
||||
}
|
||||
|
||||
// validateExtensionSlice validates a slice of extensions for path safety and limits.
|
||||
func validateExtensionSlice(slice []string, fieldName string) error {
|
||||
if len(slice) > MaxRegistryEntries {
|
||||
return fmt.Errorf("%s exceeds maximum entries (%d > %d)", fieldName, len(slice), MaxRegistryEntries)
|
||||
}
|
||||
for _, ext := range slice {
|
||||
if err := validateExtension(ext, fieldName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateExtension validates a single extension for path safety.
|
||||
//
|
||||
//revive:disable-next-line:cyclomatic
|
||||
func validateExtension(ext, context string) error {
|
||||
// Reject empty strings
|
||||
if ext == "" {
|
||||
return fmt.Errorf("%s entry cannot be empty", context)
|
||||
}
|
||||
|
||||
if len(ext) > MaxExtensionLength {
|
||||
return fmt.Errorf(
|
||||
"%s entry %q exceeds maximum length (%d > %d)",
|
||||
context, ext, len(ext), MaxExtensionLength,
|
||||
)
|
||||
}
|
||||
|
||||
// Reject absolute paths
|
||||
if filepath.IsAbs(ext) {
|
||||
return fmt.Errorf("%s entry %q is an absolute path (not allowed)", context, ext)
|
||||
}
|
||||
|
||||
// Reject path traversal
|
||||
if strings.Contains(ext, "..") {
|
||||
return fmt.Errorf("%s entry %q contains path traversal (not allowed)", context, ext)
|
||||
}
|
||||
|
||||
// For extensions, verify they start with "." or are alphanumeric
|
||||
if strings.HasPrefix(ext, ".") {
|
||||
// Reject extensions containing path separators
|
||||
if strings.ContainsRune(ext, filepath.Separator) || strings.ContainsRune(ext, '/') ||
|
||||
strings.ContainsRune(ext, '\\') {
|
||||
return fmt.Errorf("%s entry %q contains path separators (not allowed)", context, ext)
|
||||
}
|
||||
// Valid extension format
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if purely alphanumeric (for bare names)
|
||||
for _, r := range ext {
|
||||
isValid := (r >= 'a' && r <= 'z') ||
|
||||
(r >= 'A' && r <= 'Z') ||
|
||||
(r >= '0' && r <= '9') ||
|
||||
r == '_' || r == '-'
|
||||
if !isValid {
|
||||
return fmt.Errorf(
|
||||
"%s entry %q contains invalid characters (must start with '.' or be alphanumeric/_/-)",
|
||||
context,
|
||||
ext,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyCustomExtensions applies custom extensions from configuration.
|
||||
func (r *FileTypeRegistry) ApplyCustomExtensions(customImages, customBinary []string, customLanguages map[string]string) {
|
||||
func (r *FileTypeRegistry) ApplyCustomExtensions(
|
||||
customImages, customBinary []string,
|
||||
customLanguages map[string]string,
|
||||
) {
|
||||
// Add custom image extensions
|
||||
r.addExtensions(customImages, r.AddImageExtension)
|
||||
|
||||
@@ -29,12 +182,24 @@ func (r *FileTypeRegistry) addExtensions(extensions []string, adder func(string)
|
||||
|
||||
// ConfigureFromSettings applies configuration settings to the registry.
|
||||
// This function is called from main.go after config is loaded to avoid circular imports.
|
||||
func ConfigureFromSettings(
|
||||
customImages, customBinary []string,
|
||||
customLanguages map[string]string,
|
||||
disabledImages, disabledBinary, disabledLanguages []string,
|
||||
) {
|
||||
// It validates the configuration before applying it.
|
||||
func ConfigureFromSettings(config RegistryConfig) error {
|
||||
// Validate configuration first
|
||||
if err := config.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
registry := GetDefaultRegistry()
|
||||
registry.ApplyCustomExtensions(customImages, customBinary, customLanguages)
|
||||
registry.DisableExtensions(disabledImages, disabledBinary, disabledLanguages)
|
||||
|
||||
// Only apply custom extensions if they are non-empty (len() for nil slices/maps is zero)
|
||||
if len(config.CustomImages) > 0 || len(config.CustomBinary) > 0 || len(config.CustomLanguages) > 0 {
|
||||
registry.ApplyCustomExtensions(config.CustomImages, config.CustomBinary, config.CustomLanguages)
|
||||
}
|
||||
|
||||
// Only disable extensions if they are non-empty
|
||||
if len(config.DisabledImages) > 0 || len(config.DisabledBinary) > 0 || len(config.DisabledLanguages) > 0 {
|
||||
registry.DisableExtensions(config.DisabledImages, config.DisabledBinary, config.DisabledLanguages)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user