secured some implementation, check bash version

This commit is contained in:
fatalerrors
2026-03-11 11:41:56 +01:00
parent bc8cb4a237
commit e82ee06e1d

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Begin profile # Begin profile
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Copyright (c) 2013-2022 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org> # Copyright (c) 2013-2026 Geoffray Levasseur <fatalerrors@geoffray-levasseur.org>
# Protected by the BSD3 license. Please read bellow for details. # Protected by the BSD3 license. Please read bellow for details.
# #
# * Redistribution and use in source and binary forms, # * Redistribution and use in source and binary forms,
@@ -35,12 +35,19 @@
# * OF SUCH DAMAGE. # * OF SUCH DAMAGE.
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
if [[ ! $SHELL =~ bash|zsh ]]; then if [[ ! $SHELL =~ bash ]]; then
echo "That environment script is designed to be used with bash or zsh being the shell." echo "That environment script is designed to be used with bash being the shell."
echo "Please consider using bash or zsh instead, or patch me ;)!" echo "Please consider using bash to enjoy our features!"
return 1 return 1
fi fi
# Required for associative arrays (4.0+) and namerefs (4.3+)
if ((BASH_VERSINFO[0] < 4)) || [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 3 ]]; then
echo "[ Error ] This profile requires Bash 4.3 or higher."
echo "Current version: $BASH_VERSION"
return 1 2>/dev/null || exit 1
fi
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# path* : private functions for PATH variable management # path* : private functions for PATH variable management
pathremove() pathremove()
@@ -79,37 +86,43 @@ parse_conf()
{ {
local config_file="$1" local config_file="$1"
local current_section="" local current_section=""
local line key value
[[ ! -f "$config_file" ]] && return 1 [[ ! -f "$config_file" ]] && return 1
while IFS='=' read -r key value || [[ -n "$key" ]]; do while IFS='=' read -r key value || [[ -n "$key" ]]; do
# Clean key and value (strip CR and whitespace) # Internal trimming (removes leading/trailing whitespace & CR)
key=$(printf '%s' "$key" | tr -d '\r' | xargs 2>/dev/null) key="${key%"${key##*[![:space:]]}"}"
value=$(printf '%s' "$value" | tr -d '\r' | xargs 2>/dev/null) key="${key#"${key%%[![:space:]]*}"}"
key="${key%$'\r'}" # Strip potential Windows line endings
# Skip comments and empty lines # Skip comments and empty lines
[[ -z "$key" || "$key" =~ ^[#\;] ]] && continue [[ -z "$key" || "$key" =~ ^[#\;] ]] && continue
# Section Detection: [section_name] # Section Detection: [section_name]
if [[ "$key" =~ ^\[(.*)\]$ ]]; then if [[ "$key" =~ ^\[([a-zA-Z0-9_]+)\]$ ]]; then
current_section="${BASH_REMATCH[1]}" current_section="${BASH_REMATCH[1]}"
# Dynamically declare the associative array for this section
declare -g -A "CONF_$current_section" declare -g -A "CONF_$current_section"
continue continue
fi fi
# If we have a key/value pair and are inside a section # Secure Assignment (if inside a section)
if [[ -n "$current_section" && -n "$value" ]]; then if [[ -n "$current_section" ]]; then
# Strip quotes from value # Clean the value
value="${value%"${value##*[![:space:]]}"}"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%$'\r'}"
# Strip quotes (handling both " and ')
value="${value%\"}"; value="${value#\"}" value="${value%\"}"; value="${value#\"}"
value="${value%\'}"; value="${value#\'}" value="${value%\'}"; value="${value#\'}"
# Store in the dynamic array: CONF_sectionname[key]=value # Use a nameref for safe, eval-free assignment
eval "CONF_${current_section}['$key']='$value'" local -n current_array="CONF_$current_section"
current_array["$key"]="$value"
fi fi
done < "$config_file" done < "$config_file"
} }# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -118,20 +131,20 @@ load_alias()
{ {
local section_name="CONF_$1" local section_name="CONF_$1"
# Check if the associative array for this section exists # Check if the associative array exists using declare -p
if [[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]]; then [[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]] && return 1
return 1
fi
# Reference the array keys # Create a nameref to the section array
eval "local keys=\"\${!$section_name[@]}\"" local -n current_aliases="$section_name"
for key in $keys; do # Iterate safely over the keys of the associative array
# Fetch the value for this specific key for key in "${!current_aliases[@]}"; do
eval "local cmd=\"\${$section_name[$key]}\"" local cmd="${current_aliases[$key]}"
# Portability check: only alias if the command exists # Extract the base command (first word) safely without awk
local base_cmd=$(echo "$cmd" | awk '{print $1}') local base_cmd="${cmd%% *}"
# Only alias if the base command is executable
if command -v "$base_cmd" >/dev/null 2>&1; then if command -v "$base_cmd" >/dev/null 2>&1; then
alias "$key"="$cmd" alias "$key"="$cmd"
fi fi
@@ -146,16 +159,14 @@ load_conf()
{ {
local section_name="CONF_$1" local section_name="CONF_$1"
if [[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]]; then [[ "$(declare -p "$section_name" 2>/dev/null)" != "declare -A"* ]] && return 1
return 1
fi
eval "local keys=\"\${!$section_name[@]}\"" local -n current_vars="$section_name"
for key in $keys; do for key in "${!current_vars[@]}"; do
eval "local val=\"\${$section_name[$key]}\"" # Export the key/value pair as a standard shell variable
# Export as a standard shell variable # We use 'export' directly; Bash handles the assignment safely here
export "$key"="$val" export "$key"="${current_vars[$key]}"
done done
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -168,8 +179,10 @@ load_conf()
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Store script's path (realpath -s resolve symlinks if profile.sh is a symlink) # Store script's path (realpath -s resolve symlinks if profile.sh is a symlink)
# Because we're more likely to be sourced, we use BASH_SOURCE to get the path
# of the sourced file instead of $0
if [[ -z "$PROFILE_PATH" ]]; then if [[ -z "$PROFILE_PATH" ]]; then
export MYPATH=$(dirname "$(realpath -s "$0")") export MYPATH=$(dirname "$(realpath -s "${BASH_SOURCE[0]}")")
else else
export MYPATH="$PROFILE_PATH" export MYPATH="$PROFILE_PATH"
fi fi