- Fix CRITICAL: safe config parser replacing shell source, sshpass -e, CSRF with /dev/urandom, symlink-safe file I/O - Fix HIGH: input validation for timestamps/accounts, path traversal prevention in Runner.pm, AJAX CSRF on all endpoints - Fix MEDIUM: umask 077, chmod 700 on config dirs, Config.pm TOCTOU lock, rsync exit code capture bug, RSYNC_EXTRA_OPTS character validation - ShellCheck: fix word-splitting in notify.sh, safe rm in pkgacct.sh, suppress cross-file SC2034 false positives - Perl::Critic: return undef→bare return, return (sort), unpack @_, explicit return on void subs, rename Config::write→save - Remove dead code: enforce_retention_all(), rsync_dry_run() - Add require_cmd checks for rsync/ssh/hostname/gzip at startup - Escape $hint/$tip in CGI helper functions for defense-in-depth - Expand tests from 17→40: validate_timestamp, validate_account_name, _safe_source_config (including malicious input), numeric validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
68 lines
1.7 KiB
Bash
68 lines
1.7 KiB
Bash
#!/usr/bin/env bash
|
|
# gniza/lib/utils.sh — Core utility functions
|
|
|
|
die() {
|
|
local code="${2:-$EXIT_FATAL}"
|
|
echo "${C_RED}FATAL: $1${C_RESET}" >&2
|
|
exit "$code"
|
|
}
|
|
|
|
require_root() {
|
|
[[ $EUID -eq 0 ]] || die "This command must be run as root"
|
|
}
|
|
|
|
timestamp() {
|
|
date -u +"%Y-%m-%dT%H%M%S"
|
|
}
|
|
|
|
human_size() {
|
|
local bytes="$1"
|
|
if (( bytes >= 1073741824 )); then
|
|
local whole=$(( bytes / 1073741824 ))
|
|
local frac=$(( (bytes % 1073741824) * 10 / 1073741824 ))
|
|
printf "%d.%d GB" "$whole" "$frac"
|
|
elif (( bytes >= 1048576 )); then
|
|
local whole=$(( bytes / 1048576 ))
|
|
local frac=$(( (bytes % 1048576) * 10 / 1048576 ))
|
|
printf "%d.%d MB" "$whole" "$frac"
|
|
elif (( bytes >= 1024 )); then
|
|
local whole=$(( bytes / 1024 ))
|
|
local frac=$(( (bytes % 1024) * 10 / 1024 ))
|
|
printf "%d.%d KB" "$whole" "$frac"
|
|
else
|
|
printf "%d B" "$bytes"
|
|
fi
|
|
}
|
|
|
|
human_duration() {
|
|
local seconds="$1"
|
|
if (( seconds >= 3600 )); then
|
|
printf "%dh %dm %ds" $((seconds/3600)) $((seconds%3600/60)) $((seconds%60))
|
|
elif (( seconds >= 60 )); then
|
|
printf "%dm %ds" $((seconds/60)) $((seconds%60))
|
|
else
|
|
printf "%ds" "$seconds"
|
|
fi
|
|
}
|
|
|
|
# Check if a command exists
|
|
require_cmd() {
|
|
command -v "$1" &>/dev/null || die "Required command not found: $1"
|
|
}
|
|
|
|
validate_timestamp() {
|
|
local ts="$1"
|
|
if [[ ! "$ts" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{6}$ ]]; then
|
|
log_error "Invalid timestamp format: $ts (expected YYYY-MM-DDTHHMMSS)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
validate_account_name() {
|
|
local name="$1"
|
|
if [[ ! "$name" =~ ^[a-z][a-z0-9_-]{0,15}$ ]]; then
|
|
log_error "Invalid account name: $name"
|
|
return 1
|
|
fi
|
|
}
|