#!/bin/bash # LibrePortal app-config helper — root-privileged edits of specific app config # files owned by in-container UIDs (AdGuard yaml, ownCloud config.php) or host # /etc (CrowdSec bouncer). Installed root:root 0755 to /usr/local/sbin by # init.sh. Self-contained; each action edits a FIXED path with strictly-validated # arguments, so the scoped sudoers needn't grant blanket sudo awk/sed/tee/cp/mv # on those trees. Faithful ports of the original transforms. set -u [[ $EUID -eq 0 ]] || { echo "libreportal-appcfg: must run as root" >&2; exit 1; } # Baked at install; unbaked copies keep the "__" sentinel. SYSTEM_DIR="__SYSTEM_DIR__" CONTAINERS_DIR="__CONTAINERS_DIR__" [[ "$SYSTEM_DIR" == *"__"* || -z "$SYSTEM_DIR" ]] && SYSTEM_DIR="/libreportal-system" [[ "$CONTAINERS_DIR" == *"__"* || -z "$CONTAINERS_DIR" ]] && CONTAINERS_DIR="/libreportal-containers" DB_CFG="$SYSTEM_DIR/configs/general/general_docker_install" _install_user() { local u u=$(grep -h '^CFG_DOCKER_INSTALL_USER=' "$DB_CFG" 2>/dev/null | head -1 | cut -d= -f2 | awk '{print $1}') [[ -n "$u" ]] && id -u "$u" >/dev/null 2>&1 && { echo "$u"; return; } echo "dockerinstall" } # --- AdGuard: set users[0].name + password (bcrypt) in AdGuardHome.yaml -------- adguard_auth() { local user="$1" bcrypt="$2" [[ "$user" =~ ^[A-Za-z0-9._@-]+$ ]] || { echo "libreportal-appcfg: invalid adguard user" >&2; return 1; } [[ "$bcrypt" =~ ^[A-Za-z0-9./\$]+$ ]] || { echo "libreportal-appcfg: invalid bcrypt" >&2; return 1; } local yaml="$CONTAINERS_DIR/adguard/conf/AdGuardHome.yaml" [[ -f "$yaml" ]] || { echo "libreportal-appcfg: $yaml not found" >&2; return 1; } local tmp; tmp=$(mktemp) if ! awk -v u="$user" -v pw="$bcrypt" ' /^users:/ { in_users=1; print; next } in_users && /^[^[:space:]-]/ { in_users=0 } in_users && /^[[:space:]]+name:/ && !done_user { match($0, /^[[:space:]]+/); print substr($0, RSTART, RLENGTH) "name: " u; done_user=1; next } in_users && /^[[:space:]]+password:/ && !done_pw { match($0, /^[[:space:]]+/); print substr($0, RSTART, RLENGTH) "password: " pw; done_pw=1; next } { print } END { exit (done_pw ? 0 : 1) } ' "$yaml" > "$tmp"; then rm -f "$tmp" echo "libreportal-appcfg: AdGuardHome.yaml has no users password line" >&2 return 1 fi cp "$tmp" "$yaml" # overwrite content, preserve the file's existing owner rm -f "$tmp" } # --- CrowdSec: set nftables ipv4/ipv6 priority to -100 in the bouncer yaml ------ crowdsec_priority() { local cfg="/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml" [[ -f "$cfg" ]] || { echo "libreportal-appcfg: $cfg not found" >&2; return 1; } cp "$cfg" "${cfg}.bak.$(date +%Y%m%d-%H%M%S)" awk -v p="-100" ' BEGIN { in_v4=0; in_v6=0 } /^[[:space:]]*ipv4:/ { in_v4=1; in_v6=0; print; next } /^[[:space:]]*ipv6:/ { in_v6=1; in_v4=0; print; next } /^[a-zA-Z]/ { in_v4=0; in_v6=0 } in_v4 && /^[[:space:]]+priority:/ { sub(/priority:.*/, "priority: " p) } in_v6 && /^[[:space:]]+priority:/ { sub(/priority:.*/, "priority: " p) } { print } ' "$cfg" > "${cfg}.new" && mv "${cfg}.new" "$cfg" } # --- ownCloud: normalise trusted_domains + overwrite.cli.url in config.php ------ owncloud_config() { local public="$1" host_setup="$2" ip_setup="$3" public_ip="$4" [[ "$public" =~ ^(true|false)$ ]] || { echo "libreportal-appcfg: public must be true|false" >&2; return 1; } local v for v in "$host_setup" "$ip_setup" "$public_ip"; do [[ -z "$v" || "$v" =~ ^[A-Za-z0-9._:-]+$ ]] || { echo "libreportal-appcfg: invalid host/ip arg" >&2; return 1; } done local cfg_folder="$CONTAINERS_DIR/owncloud/files/config" local cfg="$cfg_folder/config.php" [[ -d "$cfg_folder" ]] || { echo "libreportal-appcfg: $cfg_folder not found" >&2; return 1; } # ownCloud writes its real config.php after first boot. Drop the default and # wait (as root — these files are owned by the in-container uid) for the # objectstore + a non-empty config.php to appear before transforming. rm -f "$cfg" local i for i in $(seq 1 60); do [[ -f "$cfg_folder/objectstore.config.php" ]] && break; sleep 5; done for i in $(seq 1 60); do [[ -f "$cfg" && -s "$cfg" ]] && break; sleep 5; done [[ -f "$cfg" && -s "$cfg" ]] || { echo "libreportal-appcfg: config.php never appeared" >&2; return 1; } local tmp; tmp=$(mktemp -d) local out="$tmp/config.php.new" cp "$cfg" "$cfg_folder/config.php.backup" awk '/'"'"'trusted_domains'"'"'/,/\),/{next} {print}' "$cfg" > "$out" sed -i '/overwrite\.cli\.url/d' "$out" sed -i '$s/);//' "$out" sed -i '/^ *$/d' "$out" if [[ "$public" == "true" ]]; then cat >> "$out" < 'https://$host_setup/', 'Overwriteprotocol' => 'https', 'trusted_domains' => array( 0 => '$host_setup', 1 => '$ip_setup', 2 => '$public_ip', ), ); EOL else cat >> "$out" < array( 0 => '$ip_setup', ), ); EOL fi mv "$out" "$cfg" chown "165568:$(_install_user)" "$cfg" rm -rf "$tmp" } action="${1:-}"; shift 2>/dev/null || true case "$action" in adguard-auth) adguard_auth "${1:-}" "${2:-}" ;; crowdsec-priority) crowdsec_priority ;; owncloud-config) owncloud_config "${1:-}" "${2:-}" "${3:-}" "${4:-}" ;; *) echo "usage: libreportal-appcfg {adguard-auth |crowdsec-priority|owncloud-config }" >&2; exit 2 ;; esac