diff --git a/install.sh b/install.sh index dc09efe..192b60b 100755 --- a/install.sh +++ b/install.sh @@ -274,6 +274,27 @@ step_services() { step_handoff() { head_ "omarchy-handoff (lan-mouse)" + # Self-sufficient on purpose: `install.sh handoff` alone brings input sharing up + # on an otherwise stock machine, without the packages/config/themes steps that + # would drag personalizations along. Everything here is idempotent, so running + # the full install.sh afterwards does no extra work. + # lan-mouse: the signed package, for the GUI/CLI and as the unpatched fallback. + # rust: only to compile handoff/patch/, removable afterwards. + # NOT python-evdev: packages.txt calls it a dependency, but omarchy-air runs + # this whole setup without it installed, so it is not required for sharing. + local need=() p + for p in lan-mouse rust; do + pacman -Qq "$p" &>/dev/null || need+=("$p") + done + if (( ${#need[@]} )); then + say " installing: ${need[*]}" + run omarchy pkg add "${need[@]}" || warn "package install failed: ${need[*]}" + else + skip "lan-mouse, rust" + fi + + install_file "$REPO/bin/omarchy-handoff" "$HOME/.local/bin/omarchy-handoff" 0755 + # 1. The patched daemon. systemd/user/lan-mouse.service points at this path, so # it has to exist before the services step enables the unit. Per-architecture: # this laptop is x86_64 and omarchy-air is aarch64, so each builds its own. @@ -289,7 +310,17 @@ step_handoff() { else err "build failed - the unit will not start until this succeeds"; fi fi - # 2. The firewall. THE bug that cost a full day: ufw is default-deny inbound, so + # 2. The unit, which points at the binary built above. + install_file "$REPO/systemd/user/lan-mouse.service" \ + "$HOME/.config/systemd/user/lan-mouse.service" 0644 + if (( ! DRY )); then + systemctl --user daemon-reload + systemctl --user is-enabled --quiet lan-mouse.service 2>/dev/null \ + && skip "lan-mouse.service already enabled" \ + || { systemctl --user enable lan-mouse.service >/dev/null && ok "enabled lan-mouse.service"; } + fi + + # 3. The firewall. THE bug that cost a full day: ufw is default-deny inbound, so # the peer's DTLS handshake dies at the wire and presents EXACTLY like a bad # certificate. Authorization is receiver-side only (connect.rs sets # insecure_skip_verify), so the RECEIVER's firewall must allow 4242/udp or @@ -298,7 +329,19 @@ step_handoff() { skip "ufw not installed - nothing to open" else local ip rules="" - # Reading the ruleset needs root, so don't probe it on a dry run. + # Both reading and changing the ruleset need root. If sudo can't run without + # a prompt and there's no terminal to prompt on, say exactly what to run + # instead of emitting raw sudo errors and half-applying. + if (( ! DRY )) && ! sudo -n true 2>/dev/null && [[ ! -t 0 ]]; then + warn "sudo needs a password and there is no terminal; run these yourself:" + for ip in "${HANDOFF_PEER_IPS[@]}"; do + say " sudo ufw allow from $ip to any port 4242 proto udp comment 'lan-mouse peer $ip'" + done + say "" + say " Without them, anything the peer INITIATES toward this machine is" + say " dropped at the wire and looks exactly like a bad certificate." + return 0 + fi (( DRY )) || rules=$(sudo ufw status 2>/dev/null || true) for ip in "${HANDOFF_PEER_IPS[@]}"; do if [[ $rules == *"4242"*"$ip"* ]]; then