package util import ( "crypto/sha1" // #nosec G505 -- SHA1 used for visual identity hashing (jdenticon compatibility), not cryptographic security "fmt" "strconv" ) // ComputeHash generates a SHA1 hash from the input string. // This matches the hash generation used by the JavaScript jdenticon library. // Note: SHA1 is used here for visual identity generation (deterministic icon creation), // not for cryptographic security purposes. func ComputeHash(input string) string { hasher := sha1.New() // #nosec G401 -- SHA1 used for visual identity hashing, not cryptographic security hasher.Write([]byte(input)) hash := hasher.Sum(nil) return fmt.Sprintf("%x", hash) } // ParseHex parses a hexadecimal value from the hash string with smart byte/character detection // This implementation is shared between engine and jdenticon packages for consistency func ParseHex(hash string, startPosition, octets int) (int, error) { // Handle negative indices (count from end like JavaScript) if startPosition < 0 { startPosition = len(hash) + startPosition } // Ensure we don't go out of bounds if startPosition < 0 || startPosition >= len(hash) { return 0, fmt.Errorf("jdenticon: hash: parsing failed: position out of bounds: position %d out of bounds for hash length %d", startPosition, len(hash)) } // If octets is 0 or negative, read from startPosition to end (like JavaScript default) end := len(hash) if octets > 0 { end = startPosition + octets if end > len(hash) { end = len(hash) } } // Extract substring and parse as hexadecimal substr := hash[startPosition:end] if len(substr) == 0 { return 0, fmt.Errorf("jdenticon: hash: parsing failed: empty substring: empty substring at position %d", startPosition) } result, err := strconv.ParseInt(substr, 16, 0) if err != nil { return 0, fmt.Errorf("jdenticon: hash: parsing failed: invalid hex format: failed to parse hex '%s' at position %d: %w", substr, startPosition, err) } return int(result), nil } // ValidateHash validates a hash string and returns detailed error information func ValidateHash(hash string) error { if len(hash) < 11 { return fmt.Errorf("jdenticon: hash: validation failed: insufficient length: hash too short: %d characters (minimum 11 required)", len(hash)) } // Check if all characters are valid hexadecimal for i, r := range hash { if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')) { return fmt.Errorf("jdenticon: hash: validation failed: invalid character: invalid hexadecimal character '%c' at position %d", r, i) } } return nil } // IsValidHash checks if a hash string is valid for jdenticon generation // This implementation is shared between engine and jdenticon packages for consistency func IsValidHash(hash string) bool { return ValidateHash(hash) == nil } // ContainsInt checks if an integer slice contains a specific value func ContainsInt(slice []int, value int) bool { for _, item := range slice { if item == value { return true } } return false }