620 lines
23 KiB
Bash
Executable File
620 lines
23 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# install.sh — curl | bash installer for sovereign_browser
|
|
#
|
|
# Installs:
|
|
# * apt runtime deps (WebKitGTK 4.1, libsoup-3, tor, build toolchain)
|
|
# * FIPS prebuilt binary from GitHub releases (source-build fallback via
|
|
# --build-fips-from-source) with CAP_NET_ADMIN
|
|
# * sovereign_browser prebuilt binary from Gitea releases (source-build fallback)
|
|
# * a `sovereign-browser` wrapper that detaches the GUI
|
|
#
|
|
# Tor and FIPS are installed by default — they are NOT optional.
|
|
#
|
|
# Usage:
|
|
# curl -fsSL <url> | bash
|
|
# curl -fsSL <url> | bash -s -- --build-from-source
|
|
# ./install.sh [options]
|
|
|
|
# --- Config --------------------------------------------------------------
|
|
|
|
GITEA_API="https://git.laantungir.net/api/v1/repos/laantungir/sovereign_browser"
|
|
GITEA_DOWNLOAD_BASE="https://git.laantungir.net/laantungir/sovereign_browser/releases/download"
|
|
SB_REPO="https://git.laantungir.net/laantungir/sovereign_browser.git"
|
|
FIPS_GITHUB_API="https://api.github.com/repos/jmcorgan/fips/releases/latest"
|
|
FIPS_REPO="https://github.com/jmcorgan/fips.git"
|
|
INSTALL_PREFIX="${INSTALL_PREFIX:-/usr/local}"
|
|
BIN_NAME="sovereign_browser"
|
|
|
|
# Runtime apt packages (non-dev). git/build-essential/pkg-config are included
|
|
# because they're needed for the FIPS source build and the source-build fallback.
|
|
APT_PACKAGES=(
|
|
libwebkit2gtk-4.1-0 libsoup-3.0-0 libqrencode4 libsqlite3-0
|
|
libsecp256k1-2 libssl3t64 libcurl4t64 zlib1g
|
|
tor git build-essential pkg-config
|
|
libcap2-bin
|
|
)
|
|
# libclang-dev is only needed when building FIPS from source (bindgen).
|
|
APT_PACKAGES_FIPS_SOURCE=(libclang-dev)
|
|
|
|
# --- Output helpers ------------------------------------------------------
|
|
|
|
if [[ -t 2 && -z "${NO_COLOR:-}" ]]; then
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
else
|
|
RED='' GREEN='' YELLOW='' BLUE='' NC=''
|
|
fi
|
|
|
|
print_info() { echo -e "${BLUE}[INFO]${NC} $*" >&2; }
|
|
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $*" >&2; }
|
|
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $*" >&2; }
|
|
print_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
|
|
die() { print_error "$*"; exit 1; }
|
|
|
|
# --- Privilege helper ----------------------------------------------------
|
|
# Returns "sudo" if the target path is not user-writable, else "".
|
|
sudo_for() {
|
|
local target="$1"
|
|
if [[ -w "$target" ]]; then
|
|
echo ""
|
|
else
|
|
command -v sudo >/dev/null 2>&1 || die "sudo is required to write to $target but is not available."
|
|
echo "sudo"
|
|
fi
|
|
}
|
|
|
|
# --- Usage ---------------------------------------------------------------
|
|
|
|
show_usage() {
|
|
cat <<'EOF'
|
|
sovereign_browser installer
|
|
|
|
Usage: curl -fsSL <url> | bash
|
|
or: curl -fsSL <url> | bash -s -- --build-from-source
|
|
or: ./install.sh [options]
|
|
|
|
Options:
|
|
--build-from-source Build sovereign_browser from source instead of
|
|
downloading the prebuilt binary
|
|
--build-fips-from-source Build FIPS from source (cargo) instead of
|
|
downloading the prebuilt binary. Slower; needs
|
|
libclang-dev (auto-installed).
|
|
--prefix <dir> Install prefix (default: /usr/local)
|
|
--yes Skip confirmation prompts
|
|
-h, --help Show this help
|
|
EOF
|
|
}
|
|
|
|
# --- Args ----------------------------------------------------------------
|
|
|
|
BUILD_FROM_SOURCE=false
|
|
BUILD_FIPS_FROM_SOURCE=false
|
|
ASSUME_YES=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--build-from-source) BUILD_FROM_SOURCE=true; shift ;;
|
|
--build-fips-from-source) BUILD_FIPS_FROM_SOURCE=true; shift ;;
|
|
--prefix) INSTALL_PREFIX="${2:-}"; shift 2 ;;
|
|
--yes|-y) ASSUME_YES=true; shift ;;
|
|
-h|--help) show_usage; exit 0 ;;
|
|
*) die "Unknown option: $1 (try --help)" ;;
|
|
esac
|
|
done
|
|
|
|
# --- Platform detection --------------------------------------------------
|
|
|
|
detect_platform() {
|
|
print_info "Detecting platform..."
|
|
local os arch
|
|
os="$(uname -s)"
|
|
arch="$(uname -m)"
|
|
|
|
[[ "$os" == "Linux" ]] || die "This installer only supports Linux (got: $os)."
|
|
|
|
if [[ "$arch" != "x86_64" ]]; then
|
|
if [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
|
|
die "arm64 is not supported for the prebuilt binary. Re-run with --build-from-source (arm64 source builds are untested)."
|
|
fi
|
|
die "Unsupported architecture: $arch (x86_64 only)."
|
|
fi
|
|
|
|
local distro_id="" version_id=""
|
|
if [[ -r /etc/os-release ]]; then
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
distro_id="${ID:-}"
|
|
version_id="${VERSION_ID:-}"
|
|
fi
|
|
|
|
local distro_ok=false
|
|
if [[ "$distro_id" == "debian" ]]; then
|
|
if [[ -n "$version_id" ]] && awk -v v="$version_id" 'BEGIN{exit !(v+0 >= 13)}'; then
|
|
distro_ok=true
|
|
fi
|
|
elif [[ "$distro_id" == "ubuntu" ]]; then
|
|
if [[ -n "$version_id" ]] && awk -v v="$version_id" 'BEGIN{exit !(v+0 >= 24.04)}'; then
|
|
distro_ok=true
|
|
fi
|
|
fi
|
|
|
|
if $distro_ok; then
|
|
print_info "Distro: $distro_id $version_id (supported)."
|
|
else
|
|
print_warning "Distro '$distro_id $version_id' is not explicitly supported."
|
|
print_warning "WebKitGTK 4.1 runtime libs are required. If apt cannot find libwebkit2gtk-4.1-0, use Debian 13 (trixie)+ or Ubuntu 24.04+."
|
|
fi
|
|
}
|
|
|
|
# --- apt dependencies ----------------------------------------------------
|
|
|
|
install_deps() {
|
|
print_info "Installing apt dependencies (runtime libs, tor, build toolchain)..."
|
|
if ! command -v sudo >/dev/null 2>&1 && [[ $EUID -ne 0 ]]; then
|
|
die "sudo is required for apt-get but is not available (not running as root)."
|
|
fi
|
|
|
|
local SUDO=""
|
|
[[ $EUID -ne 0 ]] && SUDO="sudo"
|
|
|
|
$SUDO apt-get update
|
|
if ! $SUDO apt-get install -y "${APT_PACKAGES[@]}"; then
|
|
print_error "apt-get install failed. One or more packages could not be found."
|
|
print_error "This usually means your distro is too old and lacks WebKitGTK 4.1."
|
|
print_error "Use Debian 13 (trixie) or Ubuntu 24.04+, then re-run this installer."
|
|
exit 1
|
|
fi
|
|
print_success "Dependencies installed."
|
|
}
|
|
|
|
# --- FIPS ----------------------------------------------------------------
|
|
#
|
|
# FIPS is a Rust project (https://github.com/jmcorgan/fips). It publishes
|
|
# prebuilt release tarballs on GitHub Releases containing the `fips` binary
|
|
# plus tools (fipsctl, fipstop) and systemd units. We download the prebuilt
|
|
# x86_64 Linux tarball by default — much faster than a cargo build.
|
|
#
|
|
# With --build-fips-from-source, we instead clone the repo and run
|
|
# `cargo build --release` (requires Rust 1.94.1+ via rustup, and libclang-dev
|
|
# for the rustables/bindgen nftables bindings).
|
|
|
|
# Download the prebuilt FIPS tarball from GitHub Releases and extract the
|
|
# `fips` binary. Outputs a stable binary path on stdout (the file is copied
|
|
# to a caller-managed temp file so it survives after this function returns).
|
|
# Returns non-zero on failure so the caller can fall back to a source build.
|
|
download_fips_prebuilt() {
|
|
print_info "Querying GitHub for latest FIPS release..."
|
|
local api_json tag asset_url
|
|
if ! api_json="$(curl -fsSL "$FIPS_GITHUB_API" 2>/dev/null)"; then
|
|
print_warning "Could not reach FIPS GitHub releases API."
|
|
return 1
|
|
fi
|
|
tag="$(printf '%s' "$api_json" | grep -oE '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/')"
|
|
if [[ -z "$tag" ]]; then
|
|
print_warning "Could not parse tag_name from FIPS GitHub release JSON."
|
|
return 1
|
|
fi
|
|
# Find the linux-x86_64 tarball asset URL.
|
|
asset_url="$(printf '%s' "$api_json" | grep -oE '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*linux-x86_64\.tar\.gz"' | head -1 | sed -E 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/')"
|
|
if [[ -z "$asset_url" ]]; then
|
|
print_warning "No linux-x86_64 tarball found in FIPS release $tag."
|
|
return 1
|
|
fi
|
|
|
|
# Use a temp dir for download + extraction. We do NOT use a RETURN trap
|
|
# here because the caller needs to copy the binary out after this
|
|
# function returns — a RETURN trap would delete the file first. Instead
|
|
# we copy the binary to a stable temp file and clean up the extraction
|
|
# dir ourselves before returning.
|
|
local tmp fips_bin stable
|
|
tmp="$(mktemp -d -t fips_dl.XXXXXX)"
|
|
print_info "Downloading FIPS prebuilt binary: $asset_url"
|
|
if ! curl -fsSL -o "$tmp/fips.tar.gz" "$asset_url"; then
|
|
rm -rf "$tmp"
|
|
print_warning "FIPS tarball download failed."
|
|
return 1
|
|
fi
|
|
if ! tar -xzf "$tmp/fips.tar.gz" -C "$tmp" 2>/dev/null; then
|
|
rm -rf "$tmp"
|
|
print_warning "FIPS tarball extraction failed."
|
|
return 1
|
|
fi
|
|
# The tarball extracts to fips-<ver>-linux-x86_64/fips
|
|
fips_bin="$(find "$tmp" -type f -name fips 2>/dev/null | head -1 || true)"
|
|
if [[ -z "$fips_bin" ]] || ! file "$fips_bin" 2>/dev/null | grep -qi ELF; then
|
|
rm -rf "$tmp"
|
|
print_warning "FIPS tarball did not contain an ELF 'fips' binary."
|
|
return 1
|
|
fi
|
|
# Copy to a stable path so the caller can access it after we clean up
|
|
# the extraction dir. mktemp gives a file the caller can rm later.
|
|
stable="$(mktemp -t fips_binary.XXXXXX)"
|
|
cp -f "$fips_bin" "$stable"
|
|
chmod +x "$stable"
|
|
rm -rf "$tmp"
|
|
printf '%s' "$stable"
|
|
}
|
|
|
|
# --- Rust toolchain (only for --build-fips-from-source) ------------------
|
|
|
|
FIPS_MIN_RUST_MAJOR=1
|
|
FIPS_MIN_RUST_MINOR=94
|
|
|
|
rust_version_ok() {
|
|
command -v cargo >/dev/null 2>&1 || return 1
|
|
local ver
|
|
ver="$(cargo --version 2>/dev/null | grep -oE 'cargo [0-9]+\.[0-9]+\.' | head -1 | sed 's/cargo //; s/\.$//')" || return 1
|
|
[[ -z "$ver" ]] && return 1
|
|
local major minor
|
|
major="${ver%%.*}"
|
|
minor="${ver#*.}"
|
|
[[ "$major" -gt "$FIPS_MIN_RUST_MAJOR" ]] && return 0
|
|
[[ "$major" -eq "$FIPS_MIN_RUST_MAJOR" && "$minor" -ge "$FIPS_MIN_RUST_MINOR" ]] && return 0
|
|
return 1
|
|
}
|
|
|
|
ensure_rust() {
|
|
if rust_version_ok; then
|
|
print_info "Rust toolchain OK ($(cargo --version))."
|
|
return 0
|
|
fi
|
|
|
|
if command -v cargo >/dev/null 2>&1; then
|
|
print_warning "Installed cargo ($(cargo --version)) is older than FIPS requires (1.94.1+). Installing a newer toolchain via rustup."
|
|
else
|
|
print_info "No cargo found. Installing Rust toolchain via rustup."
|
|
fi
|
|
|
|
local rustup_init
|
|
rustup_init="$(mktemp -t rustup-init.XXXXXX)"
|
|
if ! curl -fsSL --proto '=https' --tlsv1.2 -o "$rustup_init" https://sh.rustup.rs; then
|
|
rm -f "$rustup_init"
|
|
die "Failed to download rustup installer."
|
|
fi
|
|
if ! sh "$rustup_init" -y --profile minimal >/dev/null 2>&1; then
|
|
rm -f "$rustup_init"
|
|
die "rustup installation failed."
|
|
fi
|
|
rm -f "$rustup_init"
|
|
# shellcheck disable=SC1091
|
|
. "$HOME/.cargo/env" 2>/dev/null || true
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
|
|
if ! rust_version_ok; then
|
|
die "Rust toolchain installed but cargo still reports an insufficient version. FIPS requires 1.94.1+."
|
|
fi
|
|
print_success "Rust toolchain installed: $(cargo --version)."
|
|
}
|
|
|
|
# Build FIPS from source via cargo. Outputs the binary path on stdout.
|
|
build_fips_from_source() {
|
|
print_info "Building FIPS from source ($FIPS_REPO)..."
|
|
ensure_rust
|
|
|
|
local tmp
|
|
tmp="$(mktemp -d)"
|
|
trap "rm -rf '$tmp' 2>/dev/null || true" RETURN
|
|
|
|
if ! git clone --depth 1 "$FIPS_REPO" "$tmp/fips"; then
|
|
die "Failed to clone FIPS repo: $FIPS_REPO"
|
|
fi
|
|
|
|
local fips_dir="$tmp/fips"
|
|
print_info "FIPS: running cargo build --release (this can take several minutes)..."
|
|
if ! ( cd "$fips_dir" && cargo build --release ); then
|
|
die "cargo build --release failed for FIPS. FIPS is required."
|
|
fi
|
|
|
|
local fips_bin=""
|
|
for cand in \
|
|
"$fips_dir/target/release/fips" \
|
|
"$fips_dir/target/x86_64-unknown-linux-gnu/release/fips"; do
|
|
if [[ -x "$cand" ]] && file "$cand" 2>/dev/null | grep -qi ELF; then
|
|
fips_bin="$cand"
|
|
break
|
|
fi
|
|
done
|
|
if [[ -z "$fips_bin" ]]; then
|
|
fips_bin="$(find "$fips_dir/target" -type f -name fips -executable 2>/dev/null | head -1 || true)"
|
|
fi
|
|
[[ -n "$fips_bin" ]] || die "FIPS build succeeded but no 'fips' binary was found."
|
|
printf '%s' "$fips_bin"
|
|
}
|
|
|
|
install_fips() {
|
|
print_info "Installing FIPS (required, not optional)..."
|
|
|
|
# If source build was requested, install the extra build-time apt deps.
|
|
if $BUILD_FIPS_FROM_SOURCE; then
|
|
print_info "Installing FIPS source-build deps (libclang-dev for bindgen)..."
|
|
local sudo_cmd=""
|
|
if [[ $EUID -ne 0 ]]; then sudo_cmd="sudo"; fi
|
|
$sudo_cmd apt-get install -y "${APT_PACKAGES_FIPS_SOURCE[@]}" >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
local fips_bin=""
|
|
if $BUILD_FIPS_FROM_SOURCE; then
|
|
fips_bin="$(build_fips_from_source)"
|
|
else
|
|
if ! fips_bin="$(download_fips_prebuilt)"; then
|
|
print_warning "Prebuilt FIPS unavailable — falling back to source build."
|
|
# Install source-build deps on the fallback path too.
|
|
local sudo_cmd=""
|
|
if [[ $EUID -ne 0 ]]; then sudo_cmd="sudo"; fi
|
|
$sudo_cmd apt-get install -y "${APT_PACKAGES_FIPS_SOURCE[@]}" >/dev/null 2>&1 || true
|
|
fips_bin="$(build_fips_from_source)"
|
|
fi
|
|
fi
|
|
[[ -n "$fips_bin" && -x "$fips_bin" ]] || die "FIPS binary not available."
|
|
|
|
local prefix_bin="$INSTALL_PREFIX/bin"
|
|
local SUDO
|
|
SUDO="$(sudo_for "$INSTALL_PREFIX")"
|
|
$SUDO mkdir -p "$prefix_bin"
|
|
$SUDO cp -f "$fips_bin" "$prefix_bin/fips"
|
|
$SUDO chmod +x "$prefix_bin/fips"
|
|
print_success "FIPS binary installed to $prefix_bin/fips"
|
|
# Clean up the temp binary (download_fips_prebuilt copies to a stable
|
|
# mktemp file; build_fips_from_source uses a RETURN-trapped dir so its
|
|
# output is already gone, but rm -f is safe on either).
|
|
rm -f "$fips_bin" 2>/dev/null || true
|
|
|
|
# setcap for CAP_NET_ADMIN (needed to create a TUN interface in managed mode).
|
|
local setcap_cmd=""
|
|
if command -v setcap >/dev/null 2>&1; then
|
|
setcap_cmd="setcap"
|
|
elif command -v sudo >/dev/null 2>&1 && $SUDO command -v setcap >/dev/null 2>&1; then
|
|
setcap_cmd="$SUDO setcap"
|
|
fi
|
|
|
|
if [[ -n "$setcap_cmd" ]]; then
|
|
if $setcap_cmd cap_net_admin+ep "$prefix_bin/fips" 2>/dev/null; then
|
|
print_success "FIPS granted CAP_NET_ADMIN."
|
|
else
|
|
if $SUDO setcap cap_net_admin+ep "$prefix_bin/fips" 2>/dev/null; then
|
|
print_success "FIPS granted CAP_NET_ADMIN."
|
|
else
|
|
print_warning "setcap failed. FIPS managed mode (TUN) won't work without CAP_NET_ADMIN."
|
|
print_warning "Install 'libcap2-bin' and re-run, or run a system FIPS instance and set fips_mode=attach."
|
|
fi
|
|
fi
|
|
else
|
|
print_warning "'setcap' not found (libcap2-bin not installed)."
|
|
print_warning "FIPS managed mode won't work without CAP_NET_ADMIN."
|
|
print_warning "Install libcap2-bin (apt-get install -y libcap2-bin) and re-run, or run a system FIPS instance and set fips_mode=attach."
|
|
fi
|
|
}
|
|
|
|
# --- Prebuilt binary download -------------------------------------------
|
|
|
|
download_binary() {
|
|
# Outputs the downloaded binary path on stdout. Returns non-zero on failure
|
|
# so the caller can fall back to a source build.
|
|
print_info "Querying Gitea for latest release..."
|
|
local api_json tag url out
|
|
if ! api_json="$(curl -fsSL "$GITEA_API/releases/latest" 2>/dev/null)"; then
|
|
print_warning "Could not reach Gitea releases API (no release yet, or network issue)."
|
|
return 1
|
|
fi
|
|
|
|
tag="$(printf '%s' "$api_json" | grep -oE '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/')"
|
|
if [[ -z "$tag" ]]; then
|
|
print_warning "Could not parse tag_name from Gitea release JSON."
|
|
return 1
|
|
fi
|
|
|
|
url="$GITEA_DOWNLOAD_BASE/$tag/$BIN_NAME"
|
|
out="$(mktemp -t sovereign_browser_download.XXXXXX)"
|
|
print_info "Downloading prebuilt binary: $url"
|
|
if ! curl -fsSL -o "$out" "$url"; then
|
|
rm -f "$out" 2>/dev/null || true
|
|
print_warning "Download failed for $url"
|
|
return 1
|
|
fi
|
|
|
|
if ! file "$out" 2>/dev/null | grep -qi ELF; then
|
|
rm -f "$out" 2>/dev/null || true
|
|
print_warning "Downloaded file is not an ELF binary."
|
|
return 1
|
|
fi
|
|
|
|
printf '%s\n' "$out"
|
|
print_success "Downloaded sovereign_browser $tag."
|
|
}
|
|
|
|
# --- Source build fallback -----------------------------------------------
|
|
|
|
build_from_source() {
|
|
print_info "Building sovereign_browser from source ($SB_REPO)..."
|
|
local tmp
|
|
tmp="$(mktemp -d)"
|
|
trap "rm -rf '$tmp' 2>/dev/null || true" RETURN
|
|
|
|
if ! git clone --depth 1 "$SB_REPO" "$tmp/sovereign_browser"; then
|
|
die "Failed to clone sovereign_browser repo: $SB_REPO"
|
|
fi
|
|
|
|
if ! ( cd "$tmp/sovereign_browser" && make ); then
|
|
die "Source build failed (make). Ensure build deps are installed."
|
|
fi
|
|
|
|
[[ -x "$tmp/sovereign_browser/$BIN_NAME" ]] || die "Build finished but ./$BIN_NAME was not produced."
|
|
|
|
local out
|
|
out="$(mktemp -t sovereign_browser_built.XXXXXX)"
|
|
cp -f "$tmp/sovereign_browser/$BIN_NAME" "$out"
|
|
chmod +x "$out"
|
|
printf '%s\n' "$out"
|
|
print_success "Built sovereign_browser from source."
|
|
}
|
|
|
|
# --- Install binary + wrapper -------------------------------------------
|
|
|
|
install_binary() {
|
|
local src="$1"
|
|
local prefix_bin="$INSTALL_PREFIX/bin"
|
|
local SUDO
|
|
SUDO="$(sudo_for "$INSTALL_PREFIX")"
|
|
|
|
print_info "Installing binary to $prefix_bin/$BIN_NAME"
|
|
$SUDO mkdir -p "$prefix_bin"
|
|
$SUDO cp -f "$src" "$prefix_bin/$BIN_NAME"
|
|
$SUDO chmod +x "$prefix_bin/$BIN_NAME"
|
|
|
|
# Write the kebab-case wrapper that detaches the GUI.
|
|
local wrapper="$prefix_bin/sovereign-browser"
|
|
local real_bin="$prefix_bin/$BIN_NAME"
|
|
print_info "Installing wrapper to $wrapper"
|
|
|
|
# Write to a temp file then move with sudo if needed.
|
|
local wtmp
|
|
wtmp="$(mktemp -t sovereign-browser-wrapper.XXXXXX)"
|
|
cat > "$wtmp" <<WRAPPER_EOF
|
|
#!/bin/bash
|
|
# sovereign-browser — user-facing wrapper that detaches the GUI.
|
|
# Mirrors a subset of browser.sh: start | stop | restart | status | log
|
|
set -euo pipefail
|
|
|
|
SB_BIN="$real_bin"
|
|
SB_DATA_DIR="\${HOME}/.sovereign_browser"
|
|
SB_PID_FILE="\${SB_DATA_DIR}/browser.pid"
|
|
SB_LOG_FILE="\${SB_DATA_DIR}/browser.log"
|
|
|
|
sb_start() {
|
|
mkdir -p "\$SB_DATA_DIR"
|
|
# If already running, just print status.
|
|
if [[ -f "\$SB_PID_FILE" ]] && kill -0 "\$(cat "\$SB_PID_FILE" 2>/dev/null)" 2>/dev/null; then
|
|
echo "sovereign_browser already running (PID \$(cat "\$SB_PID_FILE"))" >&2
|
|
return 0
|
|
fi
|
|
nohup "\$SB_BIN" "\$@" > "\$SB_LOG_FILE" 2>&1 &
|
|
local pid=\$!
|
|
echo "\$pid" > "\$SB_PID_FILE"
|
|
disown "\$pid" 2>/dev/null || true
|
|
echo "sovereign_browser started (PID \$pid)" >&2
|
|
}
|
|
|
|
sb_stop() {
|
|
if [[ ! -f "\$SB_PID_FILE" ]]; then
|
|
echo "sovereign_browser is not running (no PID file)" >&2
|
|
return 0
|
|
fi
|
|
local pid
|
|
pid="\$(cat "\$SB_PID_FILE" 2>/dev/null || true)"
|
|
if [[ -n "\$pid" ]] && kill -0 "\$pid" 2>/dev/null; then
|
|
kill "\$pid" 2>/dev/null || true
|
|
echo "sovereign_browser stopped (PID \$pid)" >&2
|
|
else
|
|
echo "sovereign_browser was not running (stale PID file)" >&2
|
|
fi
|
|
rm -f "\$SB_PID_FILE" 2>/dev/null || true
|
|
}
|
|
|
|
sb_status() {
|
|
if [[ -f "\$SB_PID_FILE" ]] && kill -0 "\$(cat "\$SB_PID_FILE" 2>/dev/null)" 2>/dev/null; then
|
|
echo "sovereign_browser is running (PID \$(cat "\$SB_PID_FILE"))" >&2
|
|
return 0
|
|
else
|
|
echo "sovereign_browser is not running" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
sb_log() {
|
|
tail -n 50 "\$SB_LOG_FILE" 2>/dev/null || echo "(no log file yet)" >&2
|
|
}
|
|
|
|
case "\${1:-start}" in
|
|
start) shift 2>/dev/null || true; sb_start "\$@" ;;
|
|
stop) sb_stop ;;
|
|
restart) sb_stop; shift 2>/dev/null || true; sb_start "\$@" ;;
|
|
status) sb_status ;;
|
|
log) sb_log ;;
|
|
*) sb_start "\$@" ;; # default: treat all args as browser args
|
|
esac
|
|
WRAPPER_EOF
|
|
|
|
$SUDO mv -f "$wtmp" "$wrapper"
|
|
$SUDO chmod +x "$wrapper"
|
|
|
|
print_success "Wrapper installed: $wrapper"
|
|
if [[ ":${PATH}:" != *":$prefix_bin:"* ]]; then
|
|
print_warning "$prefix_bin is not in your PATH. Add it: export PATH=\"$prefix_bin:\$PATH\""
|
|
fi
|
|
}
|
|
|
|
# --- Main ----------------------------------------------------------------
|
|
|
|
main() {
|
|
detect_platform
|
|
|
|
# Summary + confirmation
|
|
local method="prebuilt binary from Gitea"
|
|
$BUILD_FROM_SOURCE && method="source build from $SB_REPO"
|
|
|
|
local fips_method="prebuilt binary from GitHub releases"
|
|
$BUILD_FIPS_FROM_SOURCE && fips_method="source build ($FIPS_REPO, cargo)"
|
|
|
|
# Use print_info so colors render via `echo -e` (a plain `cat` heredoc
|
|
# would print the literal \033 escape sequences).
|
|
print_info "sovereign_browser will be installed:"
|
|
print_info " Install prefix : $INSTALL_PREFIX"
|
|
print_info " Binary method : $method"
|
|
print_info " FIPS : $fips_method, CAP_NET_ADMIN set"
|
|
print_info " Tor : apt package 'tor'"
|
|
print_info " apt deps : ${APT_PACKAGES[*]}"
|
|
|
|
if ! $ASSUME_YES; then
|
|
print_warning "This will run apt-get install (sudo) and clone/build FIPS. Continue? [y/N]"
|
|
# Read from /dev/tty, not stdin: in `curl | bash` mode stdin is the
|
|
# curl pipe (the script text), so a plain `read` would hit EOF and
|
|
# abort immediately. /dev/tty is the user's terminal.
|
|
if [[ -r /dev/tty ]]; then
|
|
read -r reply < /dev/tty || reply=""
|
|
else
|
|
# No tty available (e.g. non-interactive CI) — require --yes.
|
|
die "No tty available for confirmation. Re-run with --yes to skip prompts."
|
|
fi
|
|
reply="${reply:-n}"
|
|
if [[ ! "${reply,,}" =~ ^y(es)?$ ]]; then
|
|
die "Aborted by user."
|
|
fi
|
|
fi
|
|
|
|
install_deps
|
|
install_fips
|
|
|
|
local bin_path=""
|
|
if $BUILD_FROM_SOURCE; then
|
|
bin_path="$(build_from_source)"
|
|
else
|
|
if ! bin_path="$(download_binary)"; then
|
|
print_warning "Prebuilt binary unavailable — falling back to source build."
|
|
bin_path="$(build_from_source)"
|
|
fi
|
|
fi
|
|
|
|
install_binary "$bin_path"
|
|
rm -f "$bin_path" 2>/dev/null || true
|
|
|
|
print_success "sovereign_browser installed."
|
|
cat >&2 <<EOF
|
|
${GREEN}[SUCCESS]${NC} Next steps:
|
|
Run: sovereign-browser
|
|
Or: sovereign-browser --login-method generate
|
|
Or: sovereign-browser --login-method generate --url https://example.com
|
|
Data dir: ~/.sovereign_browser/
|
|
Logs: sovereign-browser log
|
|
Stop: sovereign-browser stop
|
|
Status: sovereign-browser status
|
|
EOF
|
|
}
|
|
|
|
main "$@"
|