diff --git a/hosts/install.sh b/hosts/install.sh index bd80975..99ff42d 100755 --- a/hosts/install.sh +++ b/hosts/install.sh @@ -1,14 +1,107 @@ #!/bin/bash +# Re-run with sudo if not root +if [[ $EUID -ne 0 ]]; then + exec sudo -E bash "$0" "$@" +fi + # Enable systemd-resolved sudo systemctl enable systemd-resolved # Remove all attributes from /etc/hosts to allow modifications sudo chattr -i -a /etc/hosts 2>/dev/null || true -# Download the hosts file from StevenBlack's repository -echo "Downloading hosts file from StevenBlack repository..." -sudo curl -o /etc/hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn-social/hosts +# Source and local cache configuration +URL="https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn-social/hosts" +# Cache stores the RAW upstream file (without our custom modifications) +LOCAL_CACHE="/etc/hosts.stevenblack" + +# Helpers +extract_date_epoch_from_file() { + # Grep "# Date:" line and convert to epoch seconds (UTC) + local f="$1" + local line + line=$(grep -m1 '^# Date:' "$f" 2>/dev/null | sed -E 's/^# Date:[[:space:]]*(.*)[[:space:]]*\(UTC\).*/\1 UTC/') + if [[ -n "$line" ]]; then + date -u -d "$line" +%s 2>/dev/null || echo "" + else + echo "" + fi +} + +fetch_remote_header() { + # Try to fetch only the first ~4KB using HTTP Range; fallback to piping to head + local out="$1" + if curl -LfsS --max-time 10 -H 'Range: bytes=0-4095' "$URL" -o "$out"; then + return 0 + fi + # Fallback – may download more, but we only keep first lines + if curl -LfsS --max-time 10 "$URL" | head -n 20 > "$out"; then + return 0 + fi + return 1 +} + +download_remote_full_to() { + local out="$1" + curl -LfsS "$URL" -o "$out" +} + +# Decide whether to use cache or update +TMP_REMOTE_HEAD=$(mktemp) +trap 'rm -f "$TMP_REMOTE_HEAD"' EXIT + +REMOTE_AVAILABLE=0 +if fetch_remote_header "$TMP_REMOTE_HEAD"; then + REMOTE_AVAILABLE=1 +fi + +USE_CACHE=0 +NEED_UPDATE=0 + +if [[ -f "$LOCAL_CACHE" ]]; then + local_epoch=$(extract_date_epoch_from_file "$LOCAL_CACHE") +else + local_epoch="" +fi + +if [[ $REMOTE_AVAILABLE -eq 1 ]]; then + remote_epoch=$(extract_date_epoch_from_file "$TMP_REMOTE_HEAD") + if [[ -n "$local_epoch" && -n "$remote_epoch" && "$local_epoch" -ge "$remote_epoch" ]]; then + echo "Using cached StevenBlack hosts (up-to-date)." + USE_CACHE=1 + else + echo "Cached version is missing or outdated; downloading latest StevenBlack hosts..." + NEED_UPDATE=1 + fi +else + if [[ -f "$LOCAL_CACHE" ]]; then + echo "No internet; using cached StevenBlack hosts." + USE_CACHE=1 + else + echo "Error: No internet and no cached StevenBlack hosts found." >&2 + exit 1 + fi +fi + +# Ensure we have a fresh cache if needed +if [[ $NEED_UPDATE -eq 1 ]]; then + TMP_DL=$(mktemp) + if download_remote_full_to "$TMP_DL"; then + # Save raw upstream to cache + sudo mv "$TMP_DL" "$LOCAL_CACHE" + sudo chmod 644 "$LOCAL_CACHE" + echo "Saved latest StevenBlack hosts to cache: $LOCAL_CACHE" + else + rm -f "$TMP_DL" + echo "Error: Failed to download latest StevenBlack hosts." >&2 + exit 1 + fi +fi + +# Install the base hosts from cache into /etc/hosts +echo "Installing base hosts from cache to /etc/hosts..." +sudo cp "$LOCAL_CACHE" /etc/hosts # Comment out any 4chan blocking entries from the downloaded file echo "Allowing 4chan by commenting out any blocking entries..." @@ -23,7 +116,7 @@ sudo sed -i 's/^0\.0\.0\.0 messenger\.com/#0.0.0.0 messenger.com/' /etc/hosts # Add custom entries for YouTube and Discord echo "Adding custom entries for YouTube and Discord..." -sudo cat >> /etc/hosts << 'EOF' +tee -a /etc/hosts > /dev/null << 'EOF' # Custom blocking entries # YouTube diff --git a/scripts/setup_periodic_system.sh b/scripts/setup_periodic_system.sh index 360b14b..1400fcf 100755 --- a/scripts/setup_periodic_system.sh +++ b/scripts/setup_periodic_system.sh @@ -77,6 +77,7 @@ LOGROTATE_TEMPLATES="$TEMPLATES_BASE/logrotate" # Template files TEMPLATE_MAINT_SCRIPT="$BIN_TEMPLATES/periodic-system-maintenance.sh" TEMPLATE_HOSTS_MONITOR="$BIN_TEMPLATES/hosts-file-monitor.sh" +TEMPLATE_BROWSER_WRAPPER="$BIN_TEMPLATES/browser-preexec-wrapper.sh" TEMPLATE_SVC_MAINT="$SYSTEMD_TEMPLATES/periodic-system-maintenance.service" TEMPLATE_TIMER="$SYSTEMD_TEMPLATES/periodic-system-maintenance.timer" TEMPLATE_STARTUP="$SYSTEMD_TEMPLATES/periodic-system-startup.service" @@ -107,6 +108,7 @@ verify_files() { for tmpl in \ "$TEMPLATE_MAINT_SCRIPT" \ "$TEMPLATE_HOSTS_MONITOR" \ + "$TEMPLATE_BROWSER_WRAPPER" \ "$TEMPLATE_SVC_MAINT" \ "$TEMPLATE_TIMER" \ "$TEMPLATE_STARTUP" \ @@ -199,6 +201,40 @@ create_hosts_monitor_service() { echo "✓ Installed hosts monitor service from template: $monitor_service" } +# Function to install browser pre-exec wrapper and wire common browser names +install_browser_preexec_wrapper() { + echo "" + echo "6.1 Installing Browser Pre-Exec Wrapper..." + echo "=========================================" + + local wrapper="/usr/local/bin/browser-preexec-wrapper" + sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \ + "$TEMPLATE_BROWSER_WRAPPER" > "$wrapper" + chmod +x "$wrapper" + echo "✓ Installed wrapper: $wrapper" + + # Allow passwordless execution of hosts installer for root-only actions + local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd" + if command -v visudo >/dev/null 2>&1; then + echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" > "$sudoers_file" + chmod 440 "$sudoers_file" + # Validate syntax + visudo -c >/dev/null || echo "Warning: sudoers validation returned non-zero" + echo "✓ Sudoers drop-in created: $sudoers_file" + else + echo "visudo not found; skipping sudoers drop-in" + fi + + # Create symlinks for common browser commands to the wrapper in /usr/local/bin + # This takes precedence over /usr/bin in PATH on most systems. + local browsers=( "thorium-browser" "google-chrome" "google-chrome-stable" "chromium" "brave" "brave-browser" "vivaldi-stable" "firefox" ) + for b in "${browsers[@]}"; do + local link="/usr/local/bin/$b" + ln -sf "$wrapper" "$link" + done + echo "✓ Symlinked wrapper for common browsers in /usr/local/bin" +} + # Function to enable and start services enable_services() { echo "" @@ -284,6 +320,7 @@ create_systemd_service create_systemd_timer create_startup_service create_hosts_monitor_service +install_browser_preexec_wrapper enable_services create_log_rotation run_initial_execution diff --git a/scripts/system-maintenance/bin/browser-preexec-wrapper.sh b/scripts/system-maintenance/bin/browser-preexec-wrapper.sh new file mode 100644 index 0000000..58b1ad1 --- /dev/null +++ b/scripts/system-maintenance/bin/browser-preexec-wrapper.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Generic pre-exec wrapper for browsers: ensures /etc/hosts is (re)installed +# before launching the actual browser binary. + +set -euo pipefail + +HOSTS_INSTALL_SCRIPT="__HOSTS_INSTALL_SCRIPT__" + +prog_name="$(basename "$0")" +real_bin="/usr/bin/${prog_name}" + +# Best-effort: install hosts file quietly; don't block browser startup +if command -v sudo >/dev/null 2>&1; then + sudo -n "$HOSTS_INSTALL_SCRIPT" >/dev/null 2>&1 || true +else + "$HOSTS_INSTALL_SCRIPT" >/dev/null 2>&1 || true +fi + +exec "$real_bin" "$@"