mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
163 lines
4.1 KiB
Bash
163 lines
4.1 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
fail() {
|
|
echo "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
validate_single_line_value() {
|
|
local label="$1"
|
|
local value="$2"
|
|
if [[ "$value" == *$'\n'* || "$value" == *$'\r'* ]]; then
|
|
fail "Invalid $label: control characters are not allowed."
|
|
fi
|
|
}
|
|
|
|
validate_absolute_path() {
|
|
local label="$1"
|
|
local value="$2"
|
|
validate_single_line_value "$label" "$value"
|
|
[[ "$value" == /* ]] || fail "Invalid $label: expected an absolute path."
|
|
[[ "$value" != *"//"* ]] || fail "Invalid $label: repeated slashes are not allowed."
|
|
[[ "$value" != *"/./"* && "$value" != */. && "$value" != *"/../"* && "$value" != */.. ]] ||
|
|
fail "Invalid $label: dot path segments are not allowed."
|
|
}
|
|
|
|
validate_mount_source_path() {
|
|
local label="$1"
|
|
local value="$2"
|
|
validate_absolute_path "$label" "$value"
|
|
[[ "$value" != *:* ]] || fail "Invalid $label: ':' is not allowed in Podman bind-mount source paths."
|
|
}
|
|
|
|
ensure_safe_existing_dir() {
|
|
local label="$1"
|
|
local dir="$2"
|
|
validate_absolute_path "$label" "$dir"
|
|
[[ -d "$dir" ]] || fail "Missing $label: $dir"
|
|
[[ ! -L "$dir" ]] || fail "Unsafe $label: symlinks are not allowed ($dir)"
|
|
}
|
|
|
|
stat_uid() {
|
|
local path="$1"
|
|
if stat -f '%u' "$path" >/dev/null 2>&1; then
|
|
stat -f '%u' "$path"
|
|
else
|
|
stat -Lc '%u' "$path"
|
|
fi
|
|
}
|
|
|
|
stat_mode() {
|
|
local path="$1"
|
|
if stat -f '%Lp' "$path" >/dev/null 2>&1; then
|
|
stat -f '%Lp' "$path"
|
|
else
|
|
stat -Lc '%a' "$path"
|
|
fi
|
|
}
|
|
|
|
ensure_private_existing_dir_owned_by_user() {
|
|
local label="$1"
|
|
local dir="$2"
|
|
local uid=""
|
|
local mode=""
|
|
ensure_safe_existing_dir "$label" "$dir"
|
|
uid="$(stat_uid "$dir")"
|
|
[[ "$uid" == "$(id -u)" ]] || fail "Unsafe $label: not owned by current user ($dir)"
|
|
mode="$(stat_mode "$dir")"
|
|
(( (8#$mode & 0022) == 0 )) || fail "Unsafe $label: group/other writable ($dir)"
|
|
}
|
|
|
|
ensure_safe_write_file_path() {
|
|
local label="$1"
|
|
local file="$2"
|
|
local dir
|
|
validate_absolute_path "$label" "$file"
|
|
if [[ -e "$file" ]]; then
|
|
[[ ! -L "$file" ]] || fail "Unsafe $label: symlinks are not allowed ($file)"
|
|
[[ -f "$file" ]] || fail "Unsafe $label: expected a regular file ($file)"
|
|
fi
|
|
dir="$(dirname "$file")"
|
|
ensure_safe_existing_dir "${label} parent directory" "$dir"
|
|
}
|
|
|
|
write_file_atomically() {
|
|
local file="$1"
|
|
local mode="$2"
|
|
local dir=""
|
|
local tmp=""
|
|
ensure_safe_write_file_path "output file" "$file"
|
|
dir="$(dirname "$file")"
|
|
tmp="$(mktemp "$dir/.tmp.XXXXXX")"
|
|
cat >"$tmp"
|
|
chmod "$mode" "$tmp"
|
|
mv -f "$tmp" "$file"
|
|
}
|
|
|
|
validate_port() {
|
|
local label="$1"
|
|
local value="$2"
|
|
local numeric=""
|
|
[[ "$value" =~ ^[0-9]{1,5}$ ]] || fail "Invalid $label: must be numeric."
|
|
numeric=$((10#$value))
|
|
(( numeric >= 1 && numeric <= 65535 )) || fail "Invalid $label: out of range."
|
|
}
|
|
|
|
resolve_user_home() {
|
|
local user="$1"
|
|
local home=""
|
|
if command -v getent >/dev/null 2>&1; then
|
|
home="$(getent passwd "$user" 2>/dev/null | cut -d: -f6 || true)"
|
|
fi
|
|
if [[ -z "$home" && -f /etc/passwd ]]; then
|
|
home="$(awk -F: -v u="$user" '$1==u {print $6}' /etc/passwd 2>/dev/null || true)"
|
|
fi
|
|
if [[ -z "$home" ]]; then
|
|
home="/home/$user"
|
|
fi
|
|
printf '%s' "$home"
|
|
}
|
|
|
|
generate_token_hex_32() {
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
openssl rand -hex 32
|
|
return 0
|
|
fi
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
python3 - <<'PY'
|
|
import secrets
|
|
print(secrets.token_hex(32))
|
|
PY
|
|
return 0
|
|
fi
|
|
if command -v od >/dev/null 2>&1; then
|
|
od -An -N32 -tx1 /dev/urandom | tr -d " \n"
|
|
return 0
|
|
fi
|
|
echo "Missing dependency: need openssl or python3 (or od) to generate OPENCLAW_GATEWAY_TOKEN." >&2
|
|
exit 1
|
|
}
|
|
|
|
upsert_env_var() {
|
|
local file="$1"
|
|
local key="$2"
|
|
local value="$3"
|
|
local tmp
|
|
local dir
|
|
ensure_safe_write_file_path "env file" "$file"
|
|
dir="$(dirname "$file")"
|
|
tmp="$(mktemp "$dir/.env.tmp.XXXXXX")"
|
|
if [[ -f "$file" ]]; then
|
|
awk -v k="$key" -v v="$value" '
|
|
BEGIN { found = 0 }
|
|
$0 ~ ("^" k "=") { print k "=" v; found = 1; next }
|
|
{ print }
|
|
END { if (!found) print k "=" v }
|
|
' "$file" >"$tmp"
|
|
else
|
|
printf '%s=%s\n' "$key" "$value" >"$tmp"
|
|
fi
|
|
mv "$tmp" "$file"
|
|
chmod 600 "$file" 2>/dev/null || true
|
|
}
|