* Filtering feature, minor logic changes +: Add IP validation (to properly log IP even when trusted proxy is missing) +: Added synchronization of decrypted organization, collection, and folder names (for filtering purposes) +: Changed sync behavior to prevent collapsing multiple logins with the same name +: Added possibility to filter logins based on organization, collection, and folder name/id in GetSecret +: Added support for space character in secret name validation (it is also properly URL-decoded) * Update README * Fixes related to issues reported by CodeRabbit: +: Changed british use of organisations in README +: Reduced line count in parseSecretFilters by including helper function for filter dimensions resolution +: Added comment clarifying absence of existence checking on dimension IDs as opposed to names +: Removed efensive comma split logic on IPs (redundant due to IPValidation setting on Fiber) +: Changed Query validator to align with name validator (mainly removing hard-coded values) +: Added comments to decryptVaultLabel for clarity +: Change empty SyncNameMaps instance with emptySyncNameMaps helper for consistency +: Add lexical sort for lookupIDByName for deterministic result in case of multiple matches * Bumped logging to warn and added entity metadata in log * Unit tests: +: Added unit tests for every newly introduced or changed function +: Rewrote NewClient constructor to accept optional preloaded data (so it can be used in test scenarios) * Changes requested by CodeRabbit
60 lines
1.1 KiB
Go
60 lines
1.1 KiB
Go
// Package validators provides input validation for secret names
|
|
package validators
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
const SecretNameMaxLength = 255
|
|
|
|
var SecretNamePattern = regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9 _\-\./]*[a-zA-Z0-9])?$`)
|
|
|
|
func IsValidSecretName(name string) bool {
|
|
if len(name) == 0 || len(name) > SecretNameMaxLength {
|
|
return false
|
|
}
|
|
|
|
if strings.Contains(name, "..") || strings.Contains(name, "\x00") {
|
|
return false
|
|
}
|
|
|
|
for _, ch := range name {
|
|
if ch < 32 || ch > 126 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return SecretNamePattern.MatchString(name)
|
|
}
|
|
|
|
func SanitizeSecretName(name string) (string, bool) {
|
|
name = strings.TrimSpace(name)
|
|
|
|
cleaned := strings.Map(func(r rune) rune {
|
|
if r >= 32 && r <= 126 {
|
|
return r
|
|
}
|
|
return -1
|
|
}, name)
|
|
|
|
if IsValidSecretName(cleaned) {
|
|
return cleaned, true
|
|
}
|
|
|
|
return "", false
|
|
}
|
|
|
|
func IsValidFilterQueryValue(s string) bool {
|
|
s = strings.TrimSpace(s)
|
|
if s == "" || len(s) > SecretNameMaxLength {
|
|
return false
|
|
}
|
|
for _, r := range s {
|
|
if r < 32 || r == 127 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|