Commit 9f498292 authored by Lisa's avatar Lisa

fix: harden installer permission defaults

parent aa563f0a
......@@ -42,14 +42,32 @@ if ! command -v pip3 &> /dev/null; then
exit 1
fi
# Install websockets library
# Install websockets library only if missing
# On modern Debian/Ubuntu with PEP 668, system pip may be externally managed.
echo "[1/5] Installing Python dependencies..."
pip3 install --quiet websockets 2>/dev/null || pip install --quiet websockets
if [ $? -ne 0 ]; then
echo "❌ Failed to install websockets. Try: pip3 install websockets"
exit 1
if python3 -c "import websockets" 2>/dev/null; then
echo "✓ websockets library already installed"
else
PIP_OK=false
if command -v pip3 >/dev/null 2>&1; then
if pip3 install --quiet --user websockets 2>/dev/null; then
PIP_OK=true
fi
fi
if [ "$PIP_OK" != true ] && command -v pip >/dev/null 2>&1; then
if pip install --quiet --user websockets 2>/dev/null; then
PIP_OK=true
fi
fi
if [ "$PIP_OK" != true ]; then
echo "❌ Failed to install websockets in user site-packages."
echo " Try one of:"
echo " - apt install python3-websockets"
echo " - python3 -m venv ~/hermes-node-venv && ~/hermes-node-venv/bin/pip install websockets"
exit 1
fi
echo "✓ websockets library installed"
fi
echo "✓ websockets library installed"
# Determine install locations
if [ "$RUN_AS_ROOT" = true ]; then
......@@ -71,30 +89,184 @@ cp "$(pwd)/node-agent/hermes_node_agent.py" "$AGENT_DIR/hermes-node-agent"
chmod +x "$AGENT_DIR/hermes-node-agent"
echo "✓ Installed: $AGENT_DIR/hermes-node-agent"
# Create config file if missing
echo "[3/5] Checking configuration..."
if [ ! -f "$CONFIG_DIR/config.json" ]; then
echo "[4/5] Creating config file..."
TOKEN=$(python3 -c "import secrets; print(secrets.token_hex(16))")
cat > "$CONFIG_DIR/config.json" << EOF
# Create or update config interactively, using existing values as defaults
echo "[3/5] Configuring node..."
EXISTING_GATEWAY_URL="wss://YOUR-GATEWAY-HOST:8765"
EXISTING_NODE_NAME="$(hostname)"
EXISTING_TOKEN="$(python3 -c "import secrets; print(secrets.token_hex(16))")"
EXISTING_ENABLE_BROWSER="false"
EXISTING_ENABLE_COMPUTER_CONTROL="false"
EXISTING_ENABLE_DESKTOP_OBSERVE="false"
EXISTING_ENABLE_AUDIO_CONTROL="false"
if [ -f "$CONFIG_DIR/config.json" ]; then
EXISTING_GATEWAY_URL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(data.get('gateway_url', 'wss://YOUR-GATEWAY-HOST:8765'))
PY
)
EXISTING_NODE_NAME=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(data.get('node_name', '$(hostname)'))
PY
)
EXISTING_TOKEN=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(data.get('token', ''))
PY
)
EXISTING_ENABLE_BROWSER=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_browser', False))).lower())
PY
)
EXISTING_ENABLE_COMPUTER_CONTROL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_computer_control', False))).lower())
PY
)
EXISTING_ENABLE_DESKTOP_OBSERVE=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_desktop_observe', False))).lower())
PY
)
EXISTING_ENABLE_AUDIO_CONTROL=$(python3 - <<PY
import json
from pathlib import Path
p = Path(r'''$CONFIG_DIR/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_audio_control', False))).lower())
PY
)
echo " Existing config found: $CONFIG_DIR/config.json"
fi
read -r -p "Gateway URL [$EXISTING_GATEWAY_URL]: " GATEWAY_URL
GATEWAY_URL=${GATEWAY_URL:-$EXISTING_GATEWAY_URL}
read -r -p "Node name [$EXISTING_NODE_NAME]: " NODE_NAME
NODE_NAME=${NODE_NAME:-$EXISTING_NODE_NAME}
read -r -p "Token [$EXISTING_TOKEN]: " TOKEN
TOKEN=${TOKEN:-$EXISTING_TOKEN}
DEFAULT_BROWSER_CHOICE="n"
[ "$EXISTING_ENABLE_BROWSER" = "true" ] && DEFAULT_BROWSER_CHOICE="y"
read -r -p "Enable browser_control? (y/N) [$DEFAULT_BROWSER_CHOICE]: " ENABLE_BROWSER_INPUT
ENABLE_BROWSER_INPUT=${ENABLE_BROWSER_INPUT:-$DEFAULT_BROWSER_CHOICE}
case "$ENABLE_BROWSER_INPUT" in
y|Y|yes|YES) ENABLE_BROWSER=true ;;
*) ENABLE_BROWSER=false ;;
esac
DEFAULT_COMPUTER_CHOICE="n"
[ "$EXISTING_ENABLE_COMPUTER_CONTROL" = "true" ] && DEFAULT_COMPUTER_CHOICE="y"
read -r -p "Enable computer_control? (y/N) [$DEFAULT_COMPUTER_CHOICE]: " ENABLE_COMPUTER_INPUT
ENABLE_COMPUTER_INPUT=${ENABLE_COMPUTER_INPUT:-$DEFAULT_COMPUTER_CHOICE}
case "$ENABLE_COMPUTER_INPUT" in
y|Y|yes|YES) ENABLE_COMPUTER_CONTROL=true ;;
*) ENABLE_COMPUTER_CONTROL=false ;;
esac
DEFAULT_DESKTOP_CHOICE="n"
[ "$EXISTING_ENABLE_DESKTOP_OBSERVE" = "true" ] && DEFAULT_DESKTOP_CHOICE="y"
read -r -p "Enable desktop_observe? (y/N) [$DEFAULT_DESKTOP_CHOICE]: " ENABLE_DESKTOP_INPUT
ENABLE_DESKTOP_INPUT=${ENABLE_DESKTOP_INPUT:-$DEFAULT_DESKTOP_CHOICE}
case "$ENABLE_DESKTOP_INPUT" in
y|Y|yes|YES) ENABLE_DESKTOP_OBSERVE=true ;;
*) ENABLE_DESKTOP_OBSERVE=false ;;
esac
DEFAULT_AUDIO_CHOICE="n"
[ "$EXISTING_ENABLE_AUDIO_CONTROL" = "true" ] && DEFAULT_AUDIO_CHOICE="y"
read -r -p "Enable audio_control? (y/N) [$DEFAULT_AUDIO_CHOICE]: " ENABLE_AUDIO_INPUT
ENABLE_AUDIO_INPUT=${ENABLE_AUDIO_INPUT:-$DEFAULT_AUDIO_CHOICE}
case "$ENABLE_AUDIO_INPUT" in
y|Y|yes|YES) ENABLE_AUDIO_CONTROL=true ;;
*) ENABLE_AUDIO_CONTROL=false ;;
esac
CAPABILITIES='["exec"]'
if [ "$ENABLE_BROWSER" = true ]; then
CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'browser_control' not in caps:
caps.append('browser_control')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_COMPUTER_CONTROL" = true ]; then
CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'computer_control' not in caps:
caps.append('computer_control')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_DESKTOP_OBSERVE" = true ]; then
CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'desktop_observe' not in caps:
caps.append('desktop_observe')
print(json.dumps(caps))
PY
)
fi
if [ "$ENABLE_AUDIO_CONTROL" = true ]; then
CAPABILITIES=$(python3 - <<'PY' "$CAPABILITIES"
import json, sys
caps = json.loads(sys.argv[1])
if 'audio_control' not in caps:
caps.append('audio_control')
print(json.dumps(caps))
PY
)
fi
cat > "$CONFIG_DIR/config.json" << EOF
{
"gateway_url": "ws://YOUR-GATEWAY-HOST:8765",
"node_name": "$(hostname)",
"gateway_url": "$GATEWAY_URL",
"node_name": "$NODE_NAME",
"token": "$TOKEN",
"sexec_path": "$HOME/.openclaw/skills/sexec/sexec.sh",
"reconnect_interval": 5,
"heartbeat_interval": 30
"heartbeat_interval": 30,
"capabilities": $CAPABILITIES,
"enable_browser": $ENABLE_BROWSER,
"enable_computer_control": $ENABLE_COMPUTER_CONTROL,
"enable_desktop_observe": $ENABLE_DESKTOP_OBSERVE,
"enable_audio_control": $ENABLE_AUDIO_CONTROL,
"permissions": {
"deny": ["sudo", "su", "doas", "dd if=", "mkfs", "fdisk", "wipe"],
"ask": ["rm -rf", "dd if=", "> /dev/", "chmod", "chown", "mv /", ":/usr/", ":/etc/", ":/bin/", ":/sbin/"],
"allow": []
}
}
EOF
echo "✓ Config: $CONFIG_DIR/config.json"
echo ""
echo "⚠️ IMPORTANT: Edit $CONFIG_DIR/config.json"
echo " → Set gateway_url to your gateway (e.g., wss://zeiss:8765)"
echo " → Set token to match gateway's token for this node"
else
echo "[4/5] Config already exists → skipping"
echo " Config: $CONFIG_DIR/config.json"
fi
echo "[4/5] Wrote config: $CONFIG_DIR/config.json"
# Install SysV init service (root only)
if [ "$RUN_AS_ROOT" = true ] && [ -f "$SERVICE_FILE" ]; then
......
......@@ -261,7 +261,7 @@ cat > "$CONFIG_DIR/config.json" << EOF
"permissions": {
"deny": ["sudo", "su", "doas", "dd if=", "mkfs", "fdisk", "wipe"],
"ask": ["rm -rf", "dd if=", "> /dev/", "chmod", "chown", "mv /", ":/usr/", ":/etc/", ":/bin/", ":/sbin/"],
"allow": ["cat", "ls", "pwd", "cd", "echo", "head", "tail", "wc", "grep", "find", "stat", "file", "which", "whereis", "df", "du", "free", "uptime", "who", "w", "last", "ps", "top", "htop", "uname", "env", "printenv"]
"allow": []
}
}
EOF
......
......@@ -2,8 +2,16 @@
"gateway_url": "wss://YOUR-GATEWAY:8765",
"node_name": "WIN-NODE",
"token": "YOUR-TOKEN-HERE",
"sexec_path": "./sexec-template.ps1",
"reconnect_interval": 5,
"heartbeat_interval": 30,
"capabilities": ["exec", "browser_control", "computer_control"]
"capabilities": ["exec"],
"enable_browser": false,
"enable_computer_control": false,
"enable_desktop_observe": false,
"enable_audio_control": false,
"permissions": {
"deny": ["sudo", "su", "doas", "dd if=", "mkfs", "fdisk", "wipe"],
"ask": ["rm -rf", "dd if=", "> /dev/", "chmod", "chown", "mv /", ":/usr/", ":/etc/", ":/bin/", ":/sbin/"],
"allow": []
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment