feat: LeechBlock default config, Chrome repo, nsswitch fixes, extended checker

- Add leechblock_defaults.js with pre-configured blocking rules matching
  hosts/install.sh (YouTube, food delivery, fast food — 3 block sets)
- install_leechblock.sh: switch to LeechBlockNG-chrome repo, download
  jQuery UI, inject defaults.js into extension, patch background.js to
  seed storage on first run, replace browser binary in-place
- remove_guest_mode.sh: fix associative array key spacing
- enforce-nsswitch.sh: handle 'resolve' without 'dns' in emergency fix
- setup_hosts_guard.sh: ensure 'files' in nsswitch hosts line before
  snapshotting, remove erroneous 'local' outside function
- check_and_enable_services.sh: extend from 5 to 12 services, add
  nsswitch.conf validation and auto-fix
This commit is contained in:
Krzysztof Rudnicki 2026-02-20 20:24:13 +01:00
parent 4c4e966e5f
commit 09e85cd914
6 changed files with 1390 additions and 717 deletions

View File

@ -69,9 +69,15 @@ if ! validate_hosts_line "$current_hosts_line"; then
log "ERROR: Canonical source not found at $CANONICAL_SOURCE" log "ERROR: Canonical source not found at $CANONICAL_SOURCE"
# Emergency fix: add "files" back to hosts line # Emergency fix: add "files" back to hosts line
chattr -i "$TARGET" 2>/dev/null || true chattr -i "$TARGET" 2>/dev/null || true
sed -i 's/^hosts:\(.*\)dns/hosts:\1files dns/' "$TARGET" if grep -q '^hosts:.*dns' "$TARGET"; then
sed -i 's/^hosts:\(.*\)dns/hosts:\1files dns/' "$TARGET"
elif grep -q '^hosts:.*resolve' "$TARGET"; then
sed -i 's/^hosts:\(.*\)resolve/hosts: files\1resolve/' "$TARGET"
else
sed -i 's/^hosts:/hosts: files/' "$TARGET"
fi
chattr +i "$TARGET" 2>/dev/null || true chattr +i "$TARGET" 2>/dev/null || true
log "Emergency fix applied: added 'files' before 'dns'" log "Emergency fix applied: added 'files' to hosts line"
fi fi
exit 0 exit 0
fi fi

View File

@ -394,6 +394,22 @@ if [[ $ENABLE_NSSWITCH -eq 1 ]]; then
msg "Installing nsswitch enforcement script -> $INSTALL_ENFORCE_NSSWITCH" msg "Installing nsswitch enforcement script -> $INSTALL_ENFORCE_NSSWITCH"
run install -m 755 "$TEMPLATE_ENFORCE_NSSWITCH" "$INSTALL_ENFORCE_NSSWITCH" run install -m 755 "$TEMPLATE_ENFORCE_NSSWITCH" "$INSTALL_ENFORCE_NSSWITCH"
# Ensure 'files' is present in the hosts line before snapshotting
if [[ -f "$NSSWITCH" ]]; then
hosts_line=$(grep '^hosts:' "$NSSWITCH" 2>/dev/null || echo "")
if [[ -n "$hosts_line" ]] && ! echo "$hosts_line" | grep -qw 'files'; then
msg "Adding 'files' to nsswitch.conf hosts line (was: $hosts_line)"
if echo "$hosts_line" | grep -qw 'resolve'; then
run sed -i 's/^hosts:\(.*\)resolve/hosts: files\1resolve/' "$NSSWITCH"
elif echo "$hosts_line" | grep -qw 'dns'; then
run sed -i 's/^hosts:\(.*\)dns/hosts:\1files dns/' "$NSSWITCH"
else
run sed -i 's/^hosts:/hosts: files/' "$NSSWITCH"
fi
msg "nsswitch.conf hosts line fixed: $(grep '^hosts:' "$NSSWITCH")"
fi
fi
# Create nsswitch canonical snapshot if needed # Create nsswitch canonical snapshot if needed
if [[ -f "$NSSWITCH" ]]; then if [[ -f "$NSSWITCH" ]]; then
if [[ ! -f "$CANON_NSSWITCH" ]]; then if [[ ! -f "$CANON_NSSWITCH" ]]; then

File diff suppressed because it is too large Load Diff

View File

@ -15,14 +15,14 @@ warn() { printf "\033[1;33m[WARN]\033[0m %s\n" "$*"; }
err() { printf "\033[1;31m[ERR ]\033[0m %s\n" "$*"; } err() { printf "\033[1;31m[ERR ]\033[0m %s\n" "$*"; }
require_cmd() { require_cmd() {
if ! command -v "$1" > /dev/null 2>&1; then if ! command -v "$1" >/dev/null 2>&1; then
err "Missing dependency: $1" err "Missing dependency: $1"
MISSING=1 MISSING=1
fi fi
} }
usage() { usage() {
cat << EOF cat <<EOF
${SCRIPT_NAME} — Download and wire up LeechBlockNG from GitHub ${SCRIPT_NAME} — Download and wire up LeechBlockNG from GitHub
Usage: ${SCRIPT_NAME} [--version vX.Y[.Z]] [--force] [--install-firefox] Usage: ${SCRIPT_NAME} [--version vX.Y[.Z]] [--force] [--install-firefox]
@ -44,29 +44,29 @@ VERSION=""
FORCE=0 FORCE=0
AUTO_FIREFOX=0 AUTO_FIREFOX=0
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--version) --version)
VERSION="$2" VERSION="$2"
shift 2 shift 2
;; ;;
--force) --force)
FORCE=1 FORCE=1
shift shift
;; ;;
--install-firefox) --install-firefox)
AUTO_FIREFOX=1 AUTO_FIREFOX=1
shift shift
;; ;;
-h | --help) -h | --help)
usage usage
exit 0 exit 0
;; ;;
*) *)
err "Unrecognized option: $1" err "Unrecognized option: $1"
usage usage
exit 2 exit 2
;; ;;
esac esac
done done
# Dependencies # Dependencies
@ -76,45 +76,56 @@ require_cmd tar
require_cmd find require_cmd find
require_cmd sed require_cmd sed
require_cmd awk require_cmd awk
if ! command -v jq > /dev/null 2>&1; then if ! command -v jq >/dev/null 2>&1; then
warn "jq not found — will fall back to a simpler tag detection method." warn "jq not found — will fall back to a simpler tag detection method."
fi fi
[[ $MISSING -eq 1 ]] && { [[ $MISSING -eq 1 ]] && {
err "Please install missing tools and re-run." err "Please install missing tools and re-run."
exit 1 exit 1
} }
REPO_OWNER="proginosko" REPO_OWNER="proginosko"
REPO_NAME="LeechBlockNG" REPO_NAME_CHROME="LeechBlockNG-chrome"
# Firefox repo (for reference): LeechBlockNG
# Use Chrome repo for Chromium-based browsers (the default target)
REPO_NAME="$REPO_NAME_CHROME"
get_latest_tag() { get_latest_tag() {
local tag local repo="$1"
if command -v jq > /dev/null 2>&1; then local tag
tag=$(curl -fsSL "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest" | jq -r '.tag_name // empty' || true) if command -v jq >/dev/null 2>&1; then
if [[ -n $tag && $tag != "null" ]]; then tag=$(curl -fsSL "https://api.github.com/repos/${REPO_OWNER}/${repo}/releases/latest" | jq -r '.tag_name // empty' || true)
echo "$tag" if [[ -n $tag && $tag != "null" ]]; then
return 0 echo "$tag"
fi return 0
fi fi
# Fallback: follow redirect for /releases/latest to extract tag # Fallback: try tags endpoint
tag=$(curl -fsSLI "https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/latest" | awk -F'/tag/' '/^location:/I {print $2}' | tr -d '\r\n' || true) tag=$(curl -fsSL "https://api.github.com/repos/${REPO_OWNER}/${repo}/tags?per_page=1" | jq -r '.[0].name // empty' || true)
if [[ -n $tag ]]; then if [[ -n $tag && $tag != "null" ]]; then
echo "$tag" echo "$tag"
return 0 return 0
fi fi
return 1 fi
# Fallback: follow redirect for /releases/latest to extract tag
tag=$(curl -fsSLI "https://github.com/${REPO_OWNER}/${repo}/releases/latest" | awk -F'/tag/' '/^location:/I {print $2}' | tr -d '\r\n' || true)
if [[ -n $tag ]]; then
echo "$tag"
return 0
fi
return 1
} }
if [[ -z $VERSION ]]; then if [[ -z $VERSION ]]; then
info "Resolving latest release tag from GitHub…" info "Resolving latest release tag from GitHub…"
if ! VERSION=$(get_latest_tag); then if ! VERSION=$(get_latest_tag "$REPO_NAME"); then
err "Failed to determine latest version tag" err "Failed to determine latest version tag"
exit 1 exit 1
fi fi
fi fi
if [[ ! $VERSION =~ ^v?[0-9]+(\.[0-9]+)*$ ]]; then if [[ ! $VERSION =~ ^v?[0-9]+(\.[0-9]+)*$ ]]; then
warn "Version tag '$VERSION' doesn't look like vX[.Y[.Z]] — continuing anyway." warn "Version tag '$VERSION' doesn't look like vX[.Y[.Z]] — continuing anyway."
fi fi
VERSION=${VERSION#v} # strip leading v for folder names VERSION=${VERSION#v} # strip leading v for folder names
@ -126,142 +137,218 @@ VERSION_DIR="$INSTALL_ROOT/$VERSION"
CURRENT_LINK="$INSTALL_ROOT/current" CURRENT_LINK="$INSTALL_ROOT/current"
if [[ -d $VERSION_DIR && $FORCE -ne 1 ]]; then if [[ -d $VERSION_DIR && $FORCE -ne 1 ]]; then
info "LeechBlockNG $VERSION already present at $VERSION_DIR (use --force to reinstall)." info "LeechBlockNG $VERSION already present at $VERSION_DIR (use --force to reinstall)."
else else
info "Downloading LeechBlockNG $TAG source from GitHub…" info "Downloading LeechBlockNG $TAG source from GitHub…"
tmpdir=$(mktemp -d) tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT trap 'rm -rf "$tmpdir"' EXIT
ARCHIVE_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/${TAG}.tar.gz" ARCHIVE_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/archive/refs/tags/${TAG}.tar.gz"
ARCHIVE_FILE="$tmpdir/${REPO_NAME}-${TAG}.tar.gz" ARCHIVE_FILE="$tmpdir/${REPO_NAME}-${TAG}.tar.gz"
curl -fL --retry 3 -o "$ARCHIVE_FILE" "$ARCHIVE_URL" curl -fL --retry 3 -o "$ARCHIVE_FILE" "$ARCHIVE_URL"
info "Extracting…" info "Extracting…"
mkdir -p "$tmpdir/extract" mkdir -p "$tmpdir/extract"
tar -xzf "$ARCHIVE_FILE" -C "$tmpdir/extract" tar -xzf "$ARCHIVE_FILE" -C "$tmpdir/extract"
# The archive usually extracts to REPO_NAME-TAG/ … # The archive usually extracts to REPO_NAME-TAG/ …
src_root=$(find "$tmpdir/extract" -maxdepth 1 -type d -name "${REPO_NAME}-*" | head -n1 || true) src_root=$(find "$tmpdir/extract" -maxdepth 1 -type d -name "${REPO_NAME}-*" | head -n1 || true)
[[ -z $src_root ]] && { [[ -z $src_root ]] && {
err "Could not locate extracted source root" err "Could not locate extracted source root"
exit 1 exit 1
} }
# Find the extension manifest (support a couple of common layouts) # Find the extension manifest (support a couple of common layouts)
manifest_path=$(find "$src_root" -maxdepth 5 -type f -name manifest.json | head -n1 || true) manifest_path=$(find "$src_root" -maxdepth 5 -type f -name manifest.json | head -n1 || true)
if [[ -z $manifest_path ]]; then if [[ -z $manifest_path ]]; then
err "manifest.json not found in the extracted archive. The project layout may have changed." err "manifest.json not found in the extracted archive. The project layout may have changed."
exit 1 exit 1
fi fi
ext_dir=$(dirname "$manifest_path") ext_dir=$(dirname "$manifest_path")
mkdir -p "$INSTALL_ROOT" mkdir -p "$INSTALL_ROOT"
rm -rf "$VERSION_DIR" rm -rf "$VERSION_DIR"
info "Installing to $VERSION_DIR" info "Installing to $VERSION_DIR"
mkdir -p "$VERSION_DIR" mkdir -p "$VERSION_DIR"
# Copy the extension directory as-is (avoid bringing tests or build scripts) # Copy the extension directory as-is (avoid bringing tests or build scripts)
rsync -a --delete "$ext_dir/" "$VERSION_DIR/" 2> /dev/null || cp -a "$ext_dir/." "$VERSION_DIR/" rsync -a --delete "$ext_dir/" "$VERSION_DIR/" 2>/dev/null || cp -a "$ext_dir/." "$VERSION_DIR/"
ln -sfn "$VERSION_DIR" "$CURRENT_LINK" # Download jQuery UI (not included in repo — listed in .gitignore)
# The extension's options.html expects:
# jquery-ui/jquery-ui.min.css
# jquery-ui/external/jquery/jquery.js
# jquery-ui/jquery-ui.min.js
info "Downloading jQuery UI…"
jqui_version="1.14.1"
jqui_url="https://jqueryui.com/resources/download/jquery-ui-${jqui_version}.zip"
jqui_zip="$tmpdir/jquery-ui.zip"
curl -fL --retry 3 -o "$jqui_zip" "$jqui_url"
mkdir -p "$tmpdir/jqui-extract"
unzip -q "$jqui_zip" -d "$tmpdir/jqui-extract"
jqui_src=$(find "$tmpdir/jqui-extract" -maxdepth 1 -type d -name "jquery-ui-*" | head -n1 || true)
if [[ -n $jqui_src ]]; then
mkdir -p "$VERSION_DIR/jquery-ui/external/jquery"
cp "$jqui_src/jquery-ui.min.css" "$VERSION_DIR/jquery-ui/" 2>/dev/null || true
cp "$jqui_src/jquery-ui.min.js" "$VERSION_DIR/jquery-ui/" 2>/dev/null || true
cp "$jqui_src/external/jquery/jquery.js" "$VERSION_DIR/jquery-ui/external/jquery/" 2>/dev/null || true
info "✓ jQuery UI ${jqui_version} installed into extension"
else
warn "Could not extract jQuery UI — options page may not work correctly"
fi
ln -sfn "$VERSION_DIR" "$CURRENT_LINK"
fi fi
EXT_PATH="$CURRENT_LINK" # stable path used by wrappers EXT_PATH="$CURRENT_LINK" # stable path used by wrappers
# ── Inject default blocking configuration ─────────────────────────────
# Copy leechblock_defaults.js alongside the extension and patch
# background.js to import it and seed storage on first run.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULTS_SRC="$SCRIPT_DIR/leechblock_defaults.js"
if [[ -f $DEFAULTS_SRC ]]; then
cp "$DEFAULTS_SRC" "$VERSION_DIR/defaults.js"
info "Copied default blocking configuration into extension"
BG_JS="$VERSION_DIR/background.js"
if [[ -f $BG_JS ]]; then
# 1) Add importScripts("defaults.js") right after importScripts("common.js")
if ! grep -q 'importScripts("defaults.js")' "$BG_JS"; then
sed -i 's|importScripts("common.js");|importScripts("common.js");\nimportScripts("defaults.js");|' "$BG_JS"
info "Patched background.js to import defaults.js"
fi
# 2) Inject first-run seeding logic after cleanTimeData(gOptions)
if ! grep -q 'LEECHBLOCK_DEFAULTS' "$BG_JS"; then
sed -i '/cleanTimeData(gOptions);/a\
\
\t\t// ── Seed default blocking rules on first run ──\
\t\tif (typeof LEECHBLOCK_DEFAULTS !== "undefined") {\
\t\t\tlet hasAnySites = false;\
\t\t\tfor (let s = 1; s <= +gOptions["numSets"]; s++) {\
\t\t\t\tif (gOptions["sites" + s]) { hasAnySites = true; break; }\
\t\t\t}\
\t\t\tif (!hasAnySites) {\
\t\t\t\tfor (let key in LEECHBLOCK_DEFAULTS) {\
\t\t\t\t\tgOptions[key] = LEECHBLOCK_DEFAULTS[key];\
\t\t\t\t}\
\t\t\t\tcleanOptions(gOptions);\
\t\t\t\tcleanTimeData(gOptions);\
\t\t\t\tgNumSets = +gOptions["numSets"];\
\t\t\t\tgStorage.set(gOptions).catch(\
\t\t\t\t\tfunction (e) { warn("Cannot seed defaults: " + e); }\
\t\t\t\t);\
\t\t\t\tlog("Seeded default blocking configuration");\
\t\t\t}\
\t\t}' "$BG_JS"
info "Patched background.js with first-run seeding logic"
fi
fi
else
warn "leechblock_defaults.js not found at $DEFAULTS_SRC — skipping default config"
fi
# Detect browsers # Detect browsers
declare -A BROWSERS declare -A BROWSERS
BROWSERS=( BROWSERS=(
[chromium]="Chromium" [chromium]="Chromium"
[google - chrome - stable]="Google Chrome" [google - chrome - stable]="Google Chrome"
[google - chrome]="Google Chrome" [google - chrome]="Google Chrome"
[brave - browser]="Brave" [brave - browser]="Brave"
[vivaldi - stable]="Vivaldi" [vivaldi - stable]="Vivaldi"
[vivaldi]="Vivaldi" [vivaldi]="Vivaldi"
[opera]="Opera" [opera]="Opera"
[thorium - browser]="Thorium" [thorium - browser]="Thorium"
) )
declare -A FIREFOXES declare -A FIREFOXES
FIREFOXES=( FIREFOXES=(
[firefox]="Firefox" [firefox]="Firefox"
[firefox - developer - edition]="Firefox Developer Edition" [firefox - developer - edition]="Firefox Developer Edition"
[librewolf]="LibreWolf" [librewolf]="LibreWolf"
) )
found_any=0 found_any=0
wrap_bin_dir="$HOME/.local/bin"
mkdir -p "$wrap_bin_dir"
# Create a user desktop entry # Create a user desktop entry
user_apps_dir="${XDG_DATA_HOME:-$HOME/.local/share}/applications" user_apps_dir="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
mkdir -p "$user_apps_dir" mkdir -p "$user_apps_dir"
create_wrapper_and_desktop() { # Replace the system browser launcher in-place so every launch includes LeechBlock.
local bin="$1" # The original script/binary is backed up as <path>.orig.
shift # Requires sudo for system paths (/usr/bin).
local pretty="$1" replace_browser_in_place() {
shift local bin="$1"
local wrapper="$wrap_bin_dir/${bin}-with-leechblock" shift
local pretty="$1"
shift
local real_bin local real_bin
real_bin=$(command -v "$bin" || true) real_bin=$(command -v "$bin" || true)
[[ -z $real_bin ]] && return [[ -z $real_bin ]] && return
cat > "$wrapper" << WRAP # Resolve to absolute path (handles symlinks etc.)
real_bin=$(readlink -f "$real_bin")
local orig_backup="${real_bin}.orig"
# If already wrapped, skip (idempotent)
if grep -q '__LEECHBLOCK_WRAPPER__' "$real_bin" 2>/dev/null; then
info "$pretty ($bin) already wrapped — skipping"
found_any=1
return
fi
# Kill running instances so the new wrapper takes effect
info "Killing running $pretty instances…"
pkill -f "$real_bin" 2>/dev/null || true
pkill -f "$(basename "$real_bin")" 2>/dev/null || true
sleep 1
# Back up original
if [[ ! -f $orig_backup ]]; then
info "Backing up $real_bin$orig_backup"
sudo cp -a "$real_bin" "$orig_backup"
else
info "Backup already exists: $orig_backup"
fi
# Write replacement wrapper
info "Replacing $real_bin with LeechBlock wrapper…"
sudo tee "$real_bin" >/dev/null <<WRAP
#!/usr/bin/env bash #!/usr/bin/env bash
exec "$real_bin" --load-extension="$EXT_PATH" "$@" # __LEECHBLOCK_WRAPPER__ — auto-generated by install_leechblock.sh
# Original backed up at: $orig_backup
exec "$orig_backup" --load-extension="$EXT_PATH" "\$@"
WRAP WRAP
chmod +x "$wrapper" sudo chmod +x "$real_bin"
# Try to reuse icon from an existing desktop file if available info "$pretty now always launches with LeechBlock"
local sys_desktop existing_icon existing_name categories found_any=1
sys_desktop=$(grep -RIl "^Exec=.*${bin}" /usr/share/applications 2> /dev/null | head -n1 || true)
if [[ -n $sys_desktop ]]; then
existing_icon=$(awk -F= '/^Icon=/{print $2; exit}' "$sys_desktop" || true)
existing_name=$(awk -F= '/^Name=/{print $2; exit}' "$sys_desktop" || true)
categories=$(awk -F= '/^Categories=/{print $2; exit}' "$sys_desktop" || true)
fi
[[ -z $existing_icon ]] && existing_icon="$bin"
[[ -z $existing_name ]] && existing_name="$pretty"
[[ -z $categories ]] && categories="Network;WebBrowser;"
local desktop_file="$user_apps_dir/${bin}-with-leechblock.desktop"
cat > "$desktop_file" << DESK
[Desktop Entry]
Name=${existing_name} (LeechBlock)
Exec=${wrapper} %U
Terminal=false
Type=Application
Icon=${existing_icon}
Categories=${categories}
StartupNotify=true
DESK
info "Created wrapper: $wrapper"
info "Created launcher: $desktop_file"
found_any=1
} }
info "Detecting installed browsers…" info "Detecting installed browsers…"
for bin in "${!BROWSERS[@]}"; do for bin in "${!BROWSERS[@]}"; do
if command -v "$bin" > /dev/null 2>&1; then if command -v "$bin" >/dev/null 2>&1; then
create_wrapper_and_desktop "$bin" "${BROWSERS[$bin]}" replace_browser_in_place "$bin" "${BROWSERS[$bin]}"
fi fi
done done
ff_found=0 ff_found=0
for bin in "${!FIREFOXES[@]}"; do for bin in "${!FIREFOXES[@]}"; do
if command -v "$bin" > /dev/null 2>&1; then if command -v "$bin" >/dev/null 2>&1; then
ff_found=1 ff_found=1
fi fi
done done
echo echo
if [[ $found_any -eq 1 ]]; then if [[ $found_any -eq 1 ]]; then
info "Chromium-based integration complete. Launch the browser via its '(LeechBlock)' launcher." info "Chromium-based integration complete. Launch the browser via its '(LeechBlock)' launcher."
warn "Chromium will mark it as a developer extension; this is expected for unpacked installs." warn "Chromium will mark it as a developer extension; this is expected for unpacked installs."
fi fi
if [[ $ff_found -eq 1 ]]; then if [[ $ff_found -eq 1 ]]; then
echo echo
warn "Detected Firefox-based browser(s). Permanent install from GitHub source isn't possible on stable builds due to required signing." warn "Detected Firefox-based browser(s). Permanent install from GitHub source isn't possible on stable builds due to required signing."
cat << FF cat <<FF
Options: Options:
1) Install from Mozilla Add-ons (recommended): 1) Install from Mozilla Add-ons (recommended):
https://addons.mozilla.org/firefox/addon/leechblock-ng/ https://addons.mozilla.org/firefox/addon/leechblock-ng/
@ -276,8 +363,8 @@ FF
fi fi
if [[ $found_any -eq 0 && $ff_found -eq 0 ]]; then if [[ $found_any -eq 0 && $ff_found -eq 0 ]]; then
warn "No supported browsers detected. We placed the extension at: $VERSION_DIR" warn "No supported browsers detected. We placed the extension at: $VERSION_DIR"
echo "Supported (auto-wired): ${!BROWSERS[*]}. Detected Firefox variants will show guidance only." echo "Supported (auto-wired): ${!BROWSERS[*]}. Detected Firefox variants will show guidance only."
fi fi
echo echo
@ -285,36 +372,36 @@ info "Done. Version: $VERSION (tag $TAG) installed under $VERSION_DIR"
# If requested, attempt automatic install on Firefox via enterprise policies # If requested, attempt automatic install on Firefox via enterprise policies
if [[ $AUTO_FIREFOX -eq 1 && $ff_found -eq 1 ]]; then if [[ $AUTO_FIREFOX -eq 1 && $ff_found -eq 1 ]]; then
echo echo
info "Attempting Firefox auto-install via Enterprise Policies (requires sudo)." info "Attempting Firefox auto-install via Enterprise Policies (requires sudo)."
# AMO info # AMO info
ADDON_ID="leechblockng@proginosko.com" ADDON_ID="leechblockng@proginosko.com"
ADDON_AMO_URL="https://addons.mozilla.org/firefox/downloads/latest/leechblock-ng/latest.xpi" ADDON_AMO_URL="https://addons.mozilla.org/firefox/downloads/latest/leechblock-ng/latest.xpi"
# Determine policy directories for detected Firefox-like browsers # Determine policy directories for detected Firefox-like browsers
declare -a POLICY_DIRS declare -a POLICY_DIRS
POLICY_DIRS=() POLICY_DIRS=()
if command -v firefox > /dev/null 2>&1; then if command -v firefox >/dev/null 2>&1; then
POLICY_DIRS+=("/etc/firefox/policies" "/usr/lib/firefox/distribution") POLICY_DIRS+=("/etc/firefox/policies" "/usr/lib/firefox/distribution")
fi fi
if command -v firefox-developer-edition > /dev/null 2>&1; then if command -v firefox-developer-edition >/dev/null 2>&1; then
POLICY_DIRS+=("/etc/firefox-developer-edition/policies" "/usr/lib/firefox-developer-edition/distribution") POLICY_DIRS+=("/etc/firefox-developer-edition/policies" "/usr/lib/firefox-developer-edition/distribution")
fi fi
if command -v librewolf > /dev/null 2>&1; then if command -v librewolf >/dev/null 2>&1; then
POLICY_DIRS+=("/etc/librewolf/policies" "/usr/lib/librewolf/distribution") POLICY_DIRS+=("/etc/librewolf/policies" "/usr/lib/librewolf/distribution")
fi fi
# Generic mozilla path as fallback # Generic mozilla path as fallback
POLICY_DIRS+=("/usr/lib/mozilla/distribution") POLICY_DIRS+=("/usr/lib/mozilla/distribution")
updated_any=0 updated_any=0
for pol_target in "${POLICY_DIRS[@]}"; do for pol_target in "${POLICY_DIRS[@]}"; do
tmp_pol=$(mktemp) tmp_pol=$(mktemp)
existing="${pol_target}/policies.json" existing="${pol_target}/policies.json"
if sudo test -f "$existing"; then if sudo test -f "$existing"; then
info "Merging into existing policies.json at $existing" info "Merging into existing policies.json at $existing"
sudo cp "$existing" "$tmp_pol" sudo cp "$existing" "$tmp_pol"
if command -v jq > /dev/null 2>&1; then if command -v jq >/dev/null 2>&1; then
merged=$(jq --arg id "$ADDON_ID" --arg url "$ADDON_AMO_URL" ' merged=$(jq --arg id "$ADDON_ID" --arg url "$ADDON_AMO_URL" '
.policies |= (. // {}) | .policies |= (. // {}) |
.policies.ExtensionSettings |= (. // {}) | .policies.ExtensionSettings |= (. // {}) |
.policies.ExtensionSettings."*" |= (. // {"installation_mode":"allowed"}) | .policies.ExtensionSettings."*" |= (. // {"installation_mode":"allowed"}) |
@ -322,17 +409,17 @@ if [[ $AUTO_FIREFOX -eq 1 && $ff_found -eq 1 ]]; then
.policies.ExtensionSettings[$id].installation_mode = "force_installed" | .policies.ExtensionSettings[$id].installation_mode = "force_installed" |
.policies.ExtensionSettings[$id].install_url = $url .policies.ExtensionSettings[$id].install_url = $url
' "$tmp_pol") || merged="" ' "$tmp_pol") || merged=""
if [[ -n $merged ]]; then if [[ -n $merged ]]; then
printf '%s\n' "$merged" > "$tmp_pol" printf '%s\n' "$merged" >"$tmp_pol"
else else
warn "jq merge failed; skipping $pol_target" warn "jq merge failed; skipping $pol_target"
rm -f "$tmp_pol" rm -f "$tmp_pol"
continue continue
fi fi
else else
warn "jq not available; creating minimal policies.json (existing file will be backed up)." warn "jq not available; creating minimal policies.json (existing file will be backed up)."
sudo cp "$existing" "${existing}.bak.$(date +%s)" sudo cp "$existing" "${existing}.bak.$(date +%s)"
cat > "$tmp_pol" << JSON cat >"$tmp_pol" <<JSON
{ {
"policies": { "policies": {
"ExtensionSettings": { "ExtensionSettings": {
@ -345,10 +432,10 @@ if [[ $AUTO_FIREFOX -eq 1 && $ff_found -eq 1 ]]; then
} }
} }
JSON JSON
fi fi
else else
info "Creating new policies.json at $pol_target" info "Creating new policies.json at $pol_target"
cat > "$tmp_pol" << JSON cat >"$tmp_pol" <<JSON
{ {
"policies": { "policies": {
"ExtensionSettings": { "ExtensionSettings": {
@ -361,18 +448,18 @@ JSON
} }
} }
JSON JSON
fi fi
sudo mkdir -p "$pol_target" sudo mkdir -p "$pol_target"
sudo cp "$tmp_pol" "$pol_target/policies.json" sudo cp "$tmp_pol" "$pol_target/policies.json"
rm -f "$tmp_pol" rm -f "$tmp_pol"
updated_any=1 updated_any=1
done done
if [[ $updated_any -eq 1 ]]; then if [[ $updated_any -eq 1 ]]; then
info "Firefox policies updated. Restart Firefox/LibreWolf to complete installation of LeechBlock NG." info "Firefox policies updated. Restart Firefox/LibreWolf to complete installation of LeechBlock NG."
else else
warn "No Firefox policy locations updated. You may not have a supported Firefox installed." warn "No Firefox policy locations updated. You may not have a supported Firefox installed."
fi fi
info "Firefox policy updated. Restart Firefox to complete installation of LeechBlock NG." info "Firefox policy updated. Restart Firefox to complete installation of LeechBlock NG."
fi fi

View File

@ -0,0 +1,151 @@
/* LeechBlock NG default blocking configuration.
*
* Loaded by background.js via importScripts().
* On first run (no sites configured), these defaults are seeded into
* chrome.storage.local so the extension starts pre-configured.
*
* Mirrors the domains blocked in linux_configuration/hosts/install.sh.
* With matchSubdomains=true, listing "youtube.com" automatically covers
* www.youtube.com, m.youtube.com, etc.
*
* Maintained by install_leechblock.sh edit THIS file then re-run the
* installer to push changes into the extension.
*/
// eslint-disable-next-line no-unused-vars
const LEECHBLOCK_DEFAULTS = {
// ── General options ────────────────────────────────────────────────
numSets: "6",
matchSubdomains: true,
// ── Set 1 — YouTube & alternative front-ends ───────────────────────
setName1: "YouTube",
sites1: [
// Core YouTube
"youtube.com",
"youtu.be",
"youtube-nocookie.com",
"youtubei.googleapis.com",
"youtube.googleapis.com",
"yt3.ggpht.com",
"ytimg.com",
"googlevideo.com",
// Invidious instances
"invidious.io",
"invidio.us",
"vid.puffyan.us",
"yewtu.be",
"invidious.kavin.rocks",
"inv.riverside.rocks",
"invidious.namazso.eu",
"invidious.nerdvpn.de",
"invidious.projectsegfau.lt",
"invidious.slipfox.xyz",
"invidious.privacydev.net",
"invidious.perennialte.ch",
"invidious.protokoll-11.de",
"invidious.einfachzocken.eu",
"invidious.fdn.fr",
"inv.in.projectsegfau.lt",
"invidious.tiekoetter.com",
"invidious.lunar.icu",
"iv.ggtyler.dev",
"iv.melmac.space",
"invidious.incogniweb.net",
"invidious.drgns.space",
"invidious.io.lol",
"inv.n8pjl.ca",
"inv.zzls.xyz",
"inv.tux.pizza",
// Piped instances
"piped.video",
"piped.kavin.rocks",
"piped.mha.fi",
"piped.mint.lgbt",
"piped.projectsegfau.lt",
"piped.privacydev.net",
"piped.smnz.de",
"piped.adminforge.de",
"watch.whatever.social",
"piped.lunar.icu",
// Other alternative clients / front-ends
"viewtube.io",
"freetube.io",
"tubo.media",
"materialious.nadeko.net",
"clipious.org",
"newpipe.net",
"newpipe.schabi.org",
"grayjay.app",
"libretube.dev",
"hyperion.deishelon.com",
].join(" "),
times1: "0000-2400",
days1: [true, true, true, true, true, true, true],
// ── Set 2 — Food delivery services ─────────────────────────────────
setName2: "Food Delivery",
sites2: [
// Polish services
"pyszne.pl",
"glovo.com",
"glovoapp.com",
"bolt.eu",
"woltwojta.pl",
"wolt.com",
"jush.pl",
"delio.pl",
"delio.com",
"delio.com.pl",
"lisek.app",
"stava.app",
"biedronka.pl",
"barbora.pl",
"frisco.pl",
"swiatkwiatow.pl",
"szama.pl",
"auchandirect.pl",
// International services
"ubereats.com",
"uber.com",
"deliveroo.com",
"deliveroo.co.uk",
"foodpanda.com",
"grubhub.com",
"doordash.com",
"justeat.com",
"justeat.co.uk",
"postmates.com",
"seamless.com",
"menulog.com.au",
"delivery.com",
"getir.com",
"flink.com",
"gorillas.io",
"gopuff.com",
"instacart.com",
"takeaway.com",
].join(" "),
times2: "0000-2400",
days2: [true, true, true, true, true, true, true],
// ── Set 3 — Fast food chain websites ───────────────────────────────
setName3: "Fast Food",
sites3: [
"mcdonalds.com",
"mcdonalds.pl",
"kfc.com",
"kfc.pl",
"burgerking.com",
"burgerking.pl",
"pizzahut.com",
"pizzahut.pl",
"dominos.com",
"dominos.pl",
"subway.com",
"subway.pl",
].join(" "),
times3: "0000-2400",
days3: [true, true, true, true, true, true, true],
};

View File

@ -12,10 +12,10 @@ SCRIPT_NAME=$(basename "$0")
UNDO=false UNDO=false
for arg in "$@"; do for arg in "$@"; do
case "$arg" in case "$arg" in
--undo) UNDO=true ;; --undo) UNDO=true ;;
-h | --help) -h | --help)
cat << EOF cat <<EOF
Usage: $SCRIPT_NAME [--undo] Usage: $SCRIPT_NAME [--undo]
Actions: Actions:
@ -29,40 +29,40 @@ Notes:
- Requires root privileges to write to /etc/* policy paths. Will self-elevate via sudo. - Requires root privileges to write to /etc/* policy paths. Will self-elevate via sudo.
- Restart affected browsers to apply changes. - Restart affected browsers to apply changes.
EOF EOF
exit 0 exit 0
;; ;;
esac esac
done done
# Re-exec as root if needed # Re-exec as root if needed
if [[ $EUID -ne 0 ]]; then if [[ $EUID -ne 0 ]]; then
echo "[info] Elevating privileges with sudo..." echo "[info] Elevating privileges with sudo..."
exec sudo -E bash "$0" "$@" exec sudo -E bash "$0" "$@"
fi fi
# Map binaries to a logical product key # Map binaries to a logical product key
declare -A BIN_TO_KEY=( declare -A BIN_TO_KEY=(
[thorium - browser]=thorium-browser [thorium - browser]=thorium-browser
[thorium]=thorium-browser [thorium]=thorium-browser
[chromium]=chromium [chromium]=chromium
[google - chrome]=google-chrome [google - chrome]=google-chrome
[google - chrome - stable]=google-chrome [google - chrome - stable]=google-chrome
[brave - browser]=brave-browser [brave - browser]=brave-browser
[vivaldi]=vivaldi [vivaldi]=vivaldi
[vivaldi - stable]=vivaldi [vivaldi - stable]=vivaldi
[microsoft - edge - stable]=microsoft-edge-stable [microsoft - edge - stable]=microsoft-edge-stable
[opera]=opera [opera]=opera
) )
# Candidate policy directories per product key (first existing or first creatable is used) # Candidate policy directories per product key (first existing or first creatable is used)
declare -A CANDIDATE_DIRS=( declare -A CANDIDATE_DIRS=(
[thorium - browser]="/etc/thorium/policies/managed:/etc/opt/thorium/policies/managed:/etc/opt/thorium-browser/policies/managed:/etc/thorium-browser/policies/managed" [thorium - browser]="/etc/thorium/policies/managed:/etc/opt/thorium/policies/managed:/etc/opt/thorium-browser/policies/managed:/etc/thorium-browser/policies/managed"
[chromium]="/etc/chromium/policies/managed" [chromium]="/etc/chromium/policies/managed"
[google - chrome]="/etc/opt/chrome/policies/managed" [google - chrome]="/etc/opt/chrome/policies/managed"
[brave - browser]="/etc/opt/brave/policies/managed" [brave - browser]="/etc/opt/brave/policies/managed"
[vivaldi]="/etc/opt/vivaldi/policies/managed" [vivaldi]="/etc/opt/vivaldi/policies/managed"
[microsoft - edge - stable]="/etc/opt/edge/policies/managed" [microsoft - edge - stable]="/etc/opt/edge/policies/managed"
[opera]="/etc/opt/opera/policies/managed" [opera]="/etc/opt/opera/policies/managed"
) )
POLICY_FILENAME="99-disable-guest-mode.json" POLICY_FILENAME="99-disable-guest-mode.json"
@ -75,89 +75,89 @@ POLICY_JSON='{
# Discover installed browsers # Discover installed browsers
declare -A INSTALLED_KEYS=() declare -A INSTALLED_KEYS=()
for bin in "${!BIN_TO_KEY[@]}"; do for bin in "${!BIN_TO_KEY[@]}"; do
if command -v "$bin" > /dev/null 2>&1; then if command -v "$bin" >/dev/null 2>&1; then
key=${BIN_TO_KEY[$bin]} key=${BIN_TO_KEY[$bin]}
INSTALLED_KEYS[$key]=1 INSTALLED_KEYS[$key]=1
fi fi
done done
if [[ ${#INSTALLED_KEYS[@]} -eq 0 ]]; then if [[ ${#INSTALLED_KEYS[@]} -eq 0 ]]; then
echo "[warn] No supported Chromium-based browsers detected in PATH. Proceeding to configure Thorium paths anyway." echo "[warn] No supported Chromium-based browsers detected in PATH. Proceeding to configure Thorium paths anyway."
INSTALLED_KEYS[thorium - browser]=1 INSTALLED_KEYS[thorium - browser]=1
fi fi
choose_target_dir() { choose_target_dir() {
local key="$1" local key="$1"
local IFS=":" local IFS=":"
local dirs local dirs
read -r -a dirs <<< "${CANDIDATE_DIRS[$key]:-}" read -r -a dirs <<<"${CANDIDATE_DIRS[$key]:-}"
# Prefer an existing directory; else pick the first candidate # Prefer an existing directory; else pick the first candidate
for d in "${dirs[@]}"; do for d in "${dirs[@]}"; do
if [[ -d $d ]]; then if [[ -d $d ]]; then
echo "$d" echo "$d"
return 0 return 0
fi fi
done done
echo "${dirs[0]}" echo "${dirs[0]}"
} }
apply_policy() { apply_policy() {
local target_dir="$1" local target_dir="$1"
shift shift
local file="$target_dir/$POLICY_FILENAME" local file="$target_dir/$POLICY_FILENAME"
echo "[apply] $file" echo "[apply] $file"
mkdir -p "$target_dir" mkdir -p "$target_dir"
# Write atomically # Write atomically
local tmp local tmp
tmp=$(mktemp) tmp=$(mktemp)
printf '%s printf '%s
' "$POLICY_JSON" > "$tmp" ' "$POLICY_JSON" >"$tmp"
install -m 0644 "$tmp" "$file" install -m 0644 "$tmp" "$file"
rm -f "$tmp" rm -f "$tmp"
} }
remove_policy() { remove_policy() {
local target_dir="$1" local target_dir="$1"
shift shift
local file="$target_dir/$POLICY_FILENAME" local file="$target_dir/$POLICY_FILENAME"
if [[ -f $file ]]; then if [[ -f $file ]]; then
echo "[remove] $file" echo "[remove] $file"
rm -f -- "$file" rm -f -- "$file"
else else
echo "[skip] $file (not present)" echo "[skip] $file (not present)"
fi fi
} }
changed_any=false changed_any=false
for key in "${!INSTALLED_KEYS[@]}"; do for key in "${!INSTALLED_KEYS[@]}"; do
# If we somehow lack candidate dirs for a key, skip gracefully # If we somehow lack candidate dirs for a key, skip gracefully
if [[ -z ${CANDIDATE_DIRS[$key]:-} ]]; then if [[ -z ${CANDIDATE_DIRS[$key]:-} ]]; then
echo "[warn] No known policy directories for '$key'; skipping." echo "[warn] No known policy directories for '$key'; skipping."
continue continue
fi fi
target_dir=$(choose_target_dir "$key") target_dir=$(choose_target_dir "$key")
if [[ $UNDO == true ]]; then if [[ $UNDO == true ]]; then
remove_policy "$target_dir" remove_policy "$target_dir"
else else
apply_policy "$target_dir" apply_policy "$target_dir"
fi fi
changed_any=true changed_any=true
done done
if [[ $changed_any == false ]]; then if [[ $changed_any == false ]]; then
echo "[info] Nothing to do." echo "[info] Nothing to do."
fi fi
if [[ $UNDO == true ]]; then if [[ $UNDO == true ]]; then
echo "[done] Guest mode policy files removed where present. You may need to restart the browsers." echo "[done] Guest mode policy files removed where present. You may need to restart the browsers."
else else
echo "[done] Guest mode disabled via managed policies. Please fully restart affected browsers." echo "[done] Guest mode disabled via managed policies. Please fully restart affected browsers."
echo " If the Guest option still appears, it should be disabled/greyed out." echo " If the Guest option still appears, it should be disabled/greyed out."
fi fi