#!/bin/sh # Remote Control Support — agent installer for macOS and Linux. # # Served from the hub, which substitutes HUB and TOKEN below before sending it, # so the published one-liner carries the enrolment token in its URL: # # curl -fsSL https://support.freakma.com/install.sh?token=TOKEN | sh # # Fetched without a token it still works, taking one as an argument instead: # # curl -fsSL https://support.freakma.com/install.sh | sh -s -- TOKEN # # Everything lands under ~/.rcs-agent. Nothing here needs root. set -eu HUB="__HUB__" TOKEN="__TOKEN__" # Written long-hand rather than `[ $# -gt 0 ] && TOKEN="$1"`: under `set -e` the # short-circuit form leaves the script's exit status at 1 when no argument was # given, which is the normal case for the piped one-liner. if [ $# -gt 0 ]; then TOKEN="$1"; fi INSTALL_DIR="$HOME/.rcs-agent" AGENT="$INSTALL_DIR/agent.js" CONFIG="$INSTALL_DIR/config.json" SERVICE_NAME="rcs-agent" say() { printf '%s\n' "$*"; } warn() { printf '\033[33m!\033[0m %s\n' "$*" >&2; } die() { printf '\033[31mx\033[0m %s\n' "$*" >&2; exit 1; } step() { printf '\033[36m>\033[0m %s\n' "$*"; } [ -n "$TOKEN" ] || die "no enrolment token. Open the invite link on this machine, or pass one: curl -fsSL $HUB/install.sh | sh -s -- YOUR_TOKEN" case "$(uname -s)" in Darwin) PLATFORM=macos ;; Linux) PLATFORM=linux ;; *) die "$(uname -s) is not supported by this script — see $HUB/docs" ;; esac # ------------------------------------------------------------------ node # The agent uses the global WebSocket, which is only on by default from Node 22. command -v node >/dev/null 2>&1 || die "Node.js 22 or newer is required and was not found. macOS: brew install node (or https://nodejs.org) Debian: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt install -y nodejs Fedora: sudo dnf install nodejs" NODE_MAJOR=$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0) [ "$NODE_MAJOR" -ge 22 ] 2>/dev/null || die "Node.js 22 or newer is required — this machine has $(node -v). Upgrade it, or run the agent on another machine on this LAN and point it here: node agent.js enroll --vnc-host $(hostname)" # ------------------------------------------------------------------- vnc # Advisory only: the VNC server can be started after enrolment, and on a fresh # macOS the Screen Sharing toggle is usually the last thing someone does. vnc_listening() { if command -v nc >/dev/null 2>&1; then nc -z -w 2 127.0.0.1 5900 >/dev/null 2>&1; return $?; fi return 1 } if ! vnc_listening; then case "$PLATFORM" in macos) warn "nothing is listening on 127.0.0.1:5900 — turn on System Settings > General > Sharing > Screen Sharing" ;; linux) warn "nothing is listening on 127.0.0.1:5900 — start one, e.g. x11vnc -localhost -rfbport 5900" ;; esac fi # --------------------------------------------------------------- install step "installing to $INSTALL_DIR" mkdir -p "$INSTALL_DIR" curl -fsSL "$HUB/download/agent.js" -o "$AGENT" || die "could not download the agent from $HUB" step "enrolling with $HUB" node "$AGENT" enroll "$HUB/enroll/$TOKEN" --config "$CONFIG" # --------------------------------------------------------------- service NODE_BIN=$(command -v node) install_launchd() { PLIST="$HOME/Library/LaunchAgents/com.freakma.rcs-agent.plist" mkdir -p "$HOME/Library/LaunchAgents" cat > "$PLIST" < Labelcom.freakma.rcs-agent ProgramArguments $NODE_BIN $AGENT run --config $CONFIG RunAtLoad KeepAlive StandardOutPath$INSTALL_DIR/agent.log StandardErrorPath$INSTALL_DIR/agent.log PLIST_EOF launchctl unload "$PLIST" >/dev/null 2>&1 || true launchctl load "$PLIST" say "" say "Running as a launchd agent. Useful commands:" say " launchctl unload $PLIST # stop" say " launchctl load $PLIST # start" say " tail -f $INSTALL_DIR/agent.log" } install_systemd_user() { UNIT_DIR="$HOME/.config/systemd/user" mkdir -p "$UNIT_DIR" cat > "$UNIT_DIR/$SERVICE_NAME.service" </dev/null 2>&1 \ || warn "run 'sudo loginctl enable-linger $(id -un)' so the agent survives logout" } install_manual() { say "" say "No supported service manager found. Start the agent by hand:" say " node $AGENT run --config $CONFIG" } step "setting it to start automatically" case "$PLATFORM" in macos) install_launchd ;; linux) if command -v systemctl >/dev/null 2>&1 && systemctl --user show-environment >/dev/null 2>&1; then install_systemd_user else install_manual fi ;; esac say "" say "Done. This machine is registered and should now appear in the console." say "Config: $CONFIG"