mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-01-10 09:51:02 +01:00
try
This commit is contained in:
256
.claude/ha_input_validation.sh
Executable file
256
.claude/ha_input_validation.sh
Executable file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# Input Validation Library for Home Assistant Add-ons
|
||||
# Provides secure validation functions for user inputs
|
||||
set -euo pipefail
|
||||
|
||||
##################################
|
||||
# CONFIGURATION INPUT VALIDATION #
|
||||
##################################
|
||||
|
||||
# Function to validate string input with pattern
|
||||
validate_string() {
|
||||
local config_key="$1"
|
||||
local pattern="$2"
|
||||
local description="$3"
|
||||
local required="${4:-true}"
|
||||
|
||||
if ! bashio::config.has_value "$config_key"; then
|
||||
if [[ "$required" == "true" ]]; then
|
||||
bashio::log.fatal "Required configuration '$config_key' not found"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
exit 1
|
||||
else
|
||||
return 0 # Optional field not provided
|
||||
fi
|
||||
fi
|
||||
|
||||
local value
|
||||
value=$(bashio::config "$config_key")
|
||||
|
||||
if [[ ! $value =~ $pattern ]]; then
|
||||
bashio::log.fatal "Invalid format for '$config_key': '$value'"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
bashio::log.fatal "Pattern: $pattern"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bashio::log.debug "✅ Validated $config_key: $value"
|
||||
}
|
||||
|
||||
# Function to validate numeric input with bounds
|
||||
validate_numeric() {
|
||||
local config_key="$1"
|
||||
local min_val="$2"
|
||||
local max_val="$3"
|
||||
local description="$4"
|
||||
local required="${5:-true}"
|
||||
|
||||
if ! bashio::config.has_value "$config_key"; then
|
||||
if [[ "$required" == "true" ]]; then
|
||||
bashio::log.fatal "Required configuration '$config_key' not found"
|
||||
exit 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local value
|
||||
value=$(bashio::config "$config_key")
|
||||
|
||||
# Check if it's a valid number
|
||||
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
|
||||
bashio::log.fatal "Invalid numeric value for '$config_key': '$value'"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check bounds
|
||||
if [[ $value -lt $min_val ]] || [[ $value -gt $max_val ]]; then
|
||||
bashio::log.fatal "Value for '$config_key' out of range: $value"
|
||||
bashio::log.fatal "Expected: $description (range: $min_val-$max_val)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bashio::log.debug "✅ Validated $config_key: $value"
|
||||
}
|
||||
|
||||
# Function to validate boolean input
|
||||
validate_boolean() {
|
||||
local config_key="$1"
|
||||
local description="$2"
|
||||
local required="${3:-true}"
|
||||
|
||||
if ! bashio::config.has_value "$config_key"; then
|
||||
if [[ "$required" == "true" ]]; then
|
||||
bashio::log.fatal "Required configuration '$config_key' not found"
|
||||
exit 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local value
|
||||
value=$(bashio::config "$config_key")
|
||||
|
||||
if [[ ! "$value" =~ ^(true|false)$ ]]; then
|
||||
bashio::log.fatal "Invalid boolean value for '$config_key': '$value'"
|
||||
bashio::log.fatal "Expected: $description (true or false)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bashio::log.debug "✅ Validated $config_key: $value"
|
||||
}
|
||||
|
||||
# Function to validate file path (prevent directory traversal)
|
||||
validate_path() {
|
||||
local config_key="$1"
|
||||
local base_path="$2"
|
||||
local description="$3"
|
||||
local required="${4:-true}"
|
||||
|
||||
if ! bashio::config.has_value "$config_key"; then
|
||||
if [[ "$required" == "true" ]]; then
|
||||
bashio::log.fatal "Required configuration '$config_key' not found"
|
||||
exit 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local value
|
||||
value=$(bashio::config "$config_key")
|
||||
|
||||
# Check for directory traversal attempts
|
||||
if [[ "$value" =~ \.\. ]] || [[ "$value" =~ ^/ ]]; then
|
||||
bashio::log.fatal "Invalid path for '$config_key': '$value'"
|
||||
bashio::log.fatal "Path contains directory traversal or is absolute"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Normalize path and check if it's within base path
|
||||
local full_path="$base_path/$value"
|
||||
local real_path
|
||||
real_path=$(realpath -m "$full_path" 2>/dev/null || echo "$full_path")
|
||||
local real_base
|
||||
real_base=$(realpath -m "$base_path")
|
||||
|
||||
if [[ ! "$real_path" =~ ^"$real_base" ]]; then
|
||||
bashio::log.fatal "Path '$config_key' outside allowed base: '$value'"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bashio::log.debug "✅ Validated path $config_key: $value"
|
||||
}
|
||||
|
||||
# Function to validate URL
|
||||
validate_url() {
|
||||
local config_key="$1"
|
||||
local allowed_schemes="$2" # e.g., "http|https"
|
||||
local description="$3"
|
||||
local required="${4:-true}"
|
||||
|
||||
if ! bashio::config.has_value "$config_key"; then
|
||||
if [[ "$required" == "true" ]]; then
|
||||
bashio::log.fatal "Required configuration '$config_key' not found"
|
||||
exit 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local value
|
||||
value=$(bashio::config "$config_key")
|
||||
|
||||
# Basic URL validation
|
||||
local url_pattern="^($allowed_schemes)://[A-Za-z0-9.-]+(:[0-9]+)?(/.*)?$"
|
||||
|
||||
if [[ ! "$value" =~ $url_pattern ]]; then
|
||||
bashio::log.fatal "Invalid URL for '$config_key': '$value'"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
bashio::log.fatal "Allowed schemes: $allowed_schemes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bashio::log.debug "✅ Validated URL $config_key: $value"
|
||||
}
|
||||
|
||||
# Function to validate IP address
|
||||
validate_ip() {
|
||||
local config_key="$1"
|
||||
local description="$2"
|
||||
local required="${3:-true}"
|
||||
|
||||
if ! bashio::config.has_value "$config_key"; then
|
||||
if [[ "$required" == "true" ]]; then
|
||||
bashio::log.fatal "Required configuration '$config_key' not found"
|
||||
exit 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local value
|
||||
value=$(bashio::config "$config_key")
|
||||
|
||||
# IPv4 validation
|
||||
local ipv4_pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
|
||||
|
||||
if [[ "$value" =~ $ipv4_pattern ]]; then
|
||||
# Validate each octet is 0-255
|
||||
IFS='.' read -ra octets <<< "$value"
|
||||
for octet in "${octets[@]}"; do
|
||||
if [[ $octet -gt 255 ]]; then
|
||||
bashio::log.fatal "Invalid IP address for '$config_key': '$value'"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
else
|
||||
bashio::log.fatal "Invalid IP address format for '$config_key': '$value'"
|
||||
bashio::log.fatal "Expected: $description"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bashio::log.debug "✅ Validated IP $config_key: $value"
|
||||
}
|
||||
|
||||
# Function to validate common add-on configurations
|
||||
validate_common_config() {
|
||||
bashio::log.info "🔍 Validating common configuration parameters..."
|
||||
|
||||
# Validate SSL configuration if present
|
||||
if bashio::config.has_value "ssl"; then
|
||||
validate_boolean "ssl" "Enable/disable SSL"
|
||||
|
||||
if bashio::config.true "ssl"; then
|
||||
validate_string "certfile" "^[a-zA-Z0-9._-]+\.pem$" "SSL certificate filename" true
|
||||
validate_string "keyfile" "^[a-zA-Z0-9._-]+\.pem$" "SSL private key filename" true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate user/group IDs if present
|
||||
if bashio::config.has_value "PUID"; then
|
||||
validate_numeric "PUID" 0 65535 "User ID (0-65535)"
|
||||
fi
|
||||
|
||||
if bashio::config.has_value "PGID"; then
|
||||
validate_numeric "PGID" 0 65535 "Group ID (0-65535)"
|
||||
fi
|
||||
|
||||
# Validate timezone if present
|
||||
if bashio::config.has_value "TZ"; then
|
||||
validate_string "TZ" "^[A-Za-z0-9/_+-]+$" "Timezone (e.g., Europe/London)" false
|
||||
fi
|
||||
|
||||
bashio::log.info "✅ Common configuration validation completed"
|
||||
}
|
||||
|
||||
# If script is called directly, show usage
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
bashio::log.info "🛡️ Home Assistant Input Validation Library"
|
||||
bashio::log.info "This library provides secure validation functions for add-on configurations"
|
||||
echo ""
|
||||
bashio::log.info "Usage: source /ha_input_validation.sh"
|
||||
fi
|
||||
Reference in New Issue
Block a user