move himalaya wrapper from skills/himalaya/ to scripts/
The himalaya skill is a third-party ClawhHub package — putting custom scripts inside it risks conflicts on updates. The wrapper is local customization, so it belongs in scripts/ alongside email_processor.
This commit is contained in:
@@ -22,7 +22,7 @@ Use the wrapper script (`scripts/himalaya.sh`) instead of calling `himalaya` dir
|
||||
- Everything else: `envelope list`, `message read`, `message delete`, `folder`, `flag`, `attachment`, `account`, etc.
|
||||
|
||||
```bash
|
||||
HIMALAYA=~/.openclaw/workspace/skills/himalaya/scripts/himalaya.sh
|
||||
HIMALAYA=~/.openclaw/workspace/scripts/himalaya.sh
|
||||
|
||||
# All commands work the same as `himalaya`
|
||||
$HIMALAYA envelope list
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# himalaya wrapper — validates outbound email recipients against the contacts list.
|
||||
#
|
||||
# Drop-in replacement for himalaya. All commands pass through unchanged except
|
||||
# those that send email, which first validate To/Cc/Bcc recipients.
|
||||
#
|
||||
# Gated commands:
|
||||
# message send — parses MIME headers from stdin
|
||||
# template send — parses MML headers from stdin
|
||||
# message write — parses -H header flags from args
|
||||
#
|
||||
# All other commands (envelope list, message read, message delete, folder,
|
||||
# flag, attachment, account, etc.) pass through directly.
|
||||
#
|
||||
# Usage: use this script wherever you would use `himalaya`.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Config
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Find the real himalaya binary (skip this script if it's in PATH)
|
||||
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
||||
HIMALAYA=""
|
||||
while IFS= read -r candidate; do
|
||||
resolved="$(cd "$(dirname "$candidate")" && pwd)/$(basename "$candidate")"
|
||||
if [[ "$resolved" != "$SCRIPT_PATH" ]]; then
|
||||
HIMALAYA="$candidate"
|
||||
break
|
||||
fi
|
||||
done < <(which -a himalaya 2>/dev/null || true)
|
||||
|
||||
if [[ -z "$HIMALAYA" ]]; then
|
||||
# Fallback: check common locations
|
||||
for path in "$HOME/.local/bin/himalaya" /usr/local/bin/himalaya /usr/bin/himalaya; do
|
||||
if [[ -x "$path" ]]; then
|
||||
HIMALAYA="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -z "$HIMALAYA" ]]; then
|
||||
echo "Error: himalaya binary not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONTACTS="$(cd "$(dirname "$0")/../../contacts/scripts" && pwd)/contacts.py"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
validate_address() {
|
||||
local addr="$1"
|
||||
# Skip empty addresses
|
||||
[[ -z "$addr" ]] && return 0
|
||||
# Validate against contacts
|
||||
python3 "$CONTACTS" resolve "$addr" > /dev/null 2>&1
|
||||
return $?
|
||||
}
|
||||
|
||||
# Extract email address from "Display Name <email>" or bare "email" format
|
||||
extract_email() {
|
||||
local raw="$1"
|
||||
raw="$(echo "$raw" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
|
||||
if [[ "$raw" == *"<"*">"* ]]; then
|
||||
echo "$raw" | sed 's/.*<//;s/>.*//'
|
||||
else
|
||||
echo "$raw"
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate a comma-separated list of addresses. Prints errors to stderr.
|
||||
# Returns 0 if all valid, 1 if any invalid.
|
||||
validate_address_list() {
|
||||
local header_value="$1"
|
||||
local all_valid=0
|
||||
|
||||
# Split on commas
|
||||
while IFS= read -r addr; do
|
||||
addr="$(extract_email "$addr")"
|
||||
[[ -z "$addr" ]] && continue
|
||||
if ! validate_address "$addr"; then
|
||||
all_valid=1
|
||||
fi
|
||||
done < <(echo "$header_value" | tr ',' '\n')
|
||||
|
||||
return $all_valid
|
||||
}
|
||||
|
||||
# Parse To/Cc/Bcc from MIME/MML headers in a file.
|
||||
# Headers end at the first blank line.
|
||||
validate_stdin_headers() {
|
||||
local tmpfile="$1"
|
||||
local failed=0
|
||||
|
||||
# Extract header block (everything before first blank line)
|
||||
while IFS= read -r line; do
|
||||
# Stop at blank line (end of headers)
|
||||
[[ -z "$line" ]] && break
|
||||
|
||||
# Match To:, Cc:, Bcc: headers (case-insensitive)
|
||||
if echo "$line" | grep -iqE '^(to|cc|bcc):'; then
|
||||
local value
|
||||
value="$(echo "$line" | sed 's/^[^:]*:[[:space:]]*//')"
|
||||
if ! validate_address_list "$value"; then
|
||||
failed=1
|
||||
fi
|
||||
fi
|
||||
done < "$tmpfile"
|
||||
|
||||
return $failed
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Detect sending commands
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Collect all args into a string for pattern matching
|
||||
ALL_ARGS="$*"
|
||||
|
||||
# Check if this is a sending command
|
||||
is_stdin_send=false
|
||||
is_write_send=false
|
||||
|
||||
# "message send" or "template send" — reads from stdin
|
||||
if echo "$ALL_ARGS" | grep -qE '(message|template)[[:space:]]+send'; then
|
||||
is_stdin_send=true
|
||||
fi
|
||||
|
||||
# "message write" — may have -H flags with recipients
|
||||
if echo "$ALL_ARGS" | grep -qE 'message[[:space:]]+write'; then
|
||||
is_write_send=true
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Handle stdin-based sends (message send, template send)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if $is_stdin_send; then
|
||||
# Read stdin into temp file
|
||||
tmpfile="$(mktemp)"
|
||||
trap 'rm -f "$tmpfile"' EXIT
|
||||
cat > "$tmpfile"
|
||||
|
||||
# Validate recipients from headers
|
||||
if ! validate_stdin_headers "$tmpfile"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Pass through to real himalaya
|
||||
cat "$tmpfile" | exec "$HIMALAYA" "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Handle message write with -H flags
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if $is_write_send; then
|
||||
# Parse -H flags for To/Cc/Bcc without consuming args
|
||||
failed=0
|
||||
original_args=("$@")
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-H)
|
||||
shift
|
||||
if [[ $# -gt 0 ]]; then
|
||||
header="$1"
|
||||
if echo "$header" | grep -iqE '^(to|cc|bcc):'; then
|
||||
value="$(echo "$header" | sed 's/^[^:]*:[[:space:]]*//')"
|
||||
if ! validate_address_list "$value"; then
|
||||
failed=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ $failed -ne 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$HIMALAYA" "${original_args[@]}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pass through everything else
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
exec "$HIMALAYA" "$@"
|
||||
Reference in New Issue
Block a user