Snap Firefox starts the helper through the desktop portal, which reads the manifest from ~/.mozilla or /usr/lib/mozilla. The .deb and .rpm now install the manifests system-wide, and install.sh detects snap Firefox. Co-Authored-By: Claude Opus 5.5 <[email protected]>
115 lines
4.7 KiB
Bash
Executable File
115 lines
4.7 KiB
Bash
Executable File
#!/bin/sh
|
|
# Registers the Kestrove native-messaging host with the browsers of the current user (Linux, macOS).
|
|
# Windows: install.ps1.
|
|
#
|
|
# install.sh [--nmh /path/to/kestrove-nmh] [--chrome-id ID[,ID…]] [--firefox-id ID]
|
|
# [--browsers chrome,chromium,edge,brave,firefox] [--user-data-dir DIR] [--uninstall]
|
|
#
|
|
# With neither --browsers nor --user-data-dir it installs for every browser whose profile directory exists.
|
|
# --user-data-dir adds a Chromium-style profile dir started with --user-data-dir (Chromium then
|
|
# looks for NativeMessagingHosts/ inside it), e.g. for tests.
|
|
# allowed_origins / allowed_extensions pin the host to our extension ids (docs/04 A8).
|
|
set -eu
|
|
|
|
HOST=app.kestrove.nmh
|
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
|
NMH=""
|
|
# Chrome: the Chrome Web Store build, then the unpacked development build (pinned by the manifest key in
|
|
# kestrove-browser/scripts/build.mjs).
|
|
CHROME_IDS="pmhfoafjoogobhfadaicklhkldgnafmk kogapfibnnpeapfcjkkpgjddbhnjfein"
|
|
FIREFOX_ID=[email protected]
|
|
BROWSERS=""
|
|
USER_DATA_DIR=""
|
|
UNINSTALL=0
|
|
|
|
die() { echo "install.sh: $*" >&2; exit 1; }
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--nmh) NMH=$2; shift 2 ;;
|
|
--chrome-id) CHROME_IDS=$(echo "$2" | tr ',' ' '); shift 2 ;;
|
|
--firefox-id) FIREFOX_ID=$2; shift 2 ;;
|
|
--browsers) BROWSERS=$(echo "$2" | tr ',' ' '); shift 2 ;;
|
|
--user-data-dir) USER_DATA_DIR=$2; shift 2 ;;
|
|
--uninstall) UNINSTALL=1; shift ;;
|
|
-h|--help) sed -n '2,13p' "$0"; exit 0 ;;
|
|
*) die "unknown option $1" ;;
|
|
esac
|
|
done
|
|
|
|
for id in $CHROME_IDS; do echo "$id" | grep -Eq '^[a-p]{32}$' || die "--chrome-id must be 32 letters a-p"; done
|
|
# "chrome-extension://a/", "chrome-extension://b/" (the template supplies the outer quotes).
|
|
CHROME_ORIGINS=$(for id in $CHROME_IDS; do printf '%s' "${sep-}chrome-extension://$id/"; sep='", "'; done)
|
|
echo "$FIREFOX_ID" | grep -Eq '^[A-Za-z0-9._@{}-]+$' || die "bad --firefox-id"
|
|
|
|
if [ "$UNINSTALL" = 0 ]; then
|
|
if [ -z "$NMH" ]; then
|
|
# Next to this script (installed layout), else the cargo build output (development).
|
|
for c in "$HERE/kestrove-nmh" "$HERE/../src-tauri/target/release/kestrove-nmh" "$HERE/../src-tauri/target/debug/kestrove-nmh"; do
|
|
[ -x "$c" ] && NMH=$c && break
|
|
done
|
|
fi
|
|
[ -n "$NMH" ] || die "kestrove-nmh not found; pass --nmh"
|
|
[ -x "$NMH" ] || die "$NMH is not executable"
|
|
NMH=$(cd "$(dirname "$NMH")" && pwd)/$(basename "$NMH")
|
|
case "$NMH" in *[\"\\\|\&]*) die "the host path may not contain quotes, backslashes, | or &" ;; esac
|
|
fi
|
|
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
# The Kestrove Mac app registers its own host on launch; this points the browsers at a desktop dev build.
|
|
[ "$UNINSTALL" = 1 ] || echo "note: on macOS the Kestrove app registers itself; re-open it to switch back" >&2
|
|
BASE="$HOME/Library/Application Support"
|
|
dir_chrome="$BASE/Google/Chrome"
|
|
dir_chromium="$BASE/Chromium"
|
|
dir_edge="$BASE/Microsoft Edge"
|
|
dir_brave="$BASE/BraveSoftware/Brave-Browser"
|
|
dir_firefox="$BASE/Mozilla"
|
|
ff_sub=NativeMessagingHosts
|
|
;;
|
|
Linux)
|
|
CFG=${XDG_CONFIG_HOME:-$HOME/.config}
|
|
dir_chrome="$CFG/google-chrome"
|
|
dir_chromium="$CFG/chromium"
|
|
dir_edge="$CFG/microsoft-edge"
|
|
dir_brave="$CFG/BraveSoftware/Brave-Browser"
|
|
dir_firefox="$HOME/.mozilla"
|
|
ff_sub=native-messaging-hosts
|
|
;;
|
|
*) die "unsupported OS $(uname -s); on Windows use install.ps1" ;;
|
|
esac
|
|
|
|
# Auto-detect only when nothing was named: a test run with --user-data-dir must not touch real profiles.
|
|
[ -n "$BROWSERS$USER_DATA_DIR" ] || for b in chrome chromium edge brave firefox; do
|
|
eval "d=\$dir_$b"
|
|
[ -d "$d" ] && BROWSERS="$BROWSERS $b"
|
|
done
|
|
# Snap Firefox keeps its profile in ~/snap, but its portal reads the host from ~/.mozilla like any other Firefox.
|
|
case " $BROWSERS " in *" firefox "*) ;; *)
|
|
[ -n "$USER_DATA_DIR" ] || { [ -d /snap/firefox ] && BROWSERS="$BROWSERS firefox"; } || true ;;
|
|
esac
|
|
|
|
render() { # template → stdout
|
|
sed -e "s|__NMH_PATH__|$NMH|" -e "s|chrome-extension://__CHROME_EXTENSION_ID__/|$CHROME_ORIGINS|" -e "s|__FIREFOX_EXTENSION_ID__|$FIREFOX_ID|" "$HERE/$HOST.$1.json"
|
|
}
|
|
|
|
place() { # flavor dir
|
|
if [ "$UNINSTALL" = 1 ]; then
|
|
rm -f "$2/$HOST.json" && echo "removed $2/$HOST.json"
|
|
else
|
|
mkdir -p "$2"
|
|
render "$1" > "$2/$HOST.json.tmp" && chmod 644 "$2/$HOST.json.tmp" && mv "$2/$HOST.json.tmp" "$2/$HOST.json"
|
|
echo "installed $2/$HOST.json"
|
|
fi
|
|
}
|
|
|
|
for b in $BROWSERS; do
|
|
case "$b" in
|
|
chrome|chromium|edge|brave) eval "d=\$dir_$b"; place chrome "$d/NativeMessagingHosts" ;;
|
|
firefox) place firefox "$dir_firefox/$ff_sub" ;;
|
|
*) die "unknown browser $b" ;;
|
|
esac
|
|
done
|
|
[ -z "$USER_DATA_DIR" ] || place chrome "$USER_DATA_DIR/NativeMessagingHosts"
|
|
[ -n "$BROWSERS$USER_DATA_DIR" ] || echo "no supported browser profile found (use --browsers)"
|