123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- #!/bin/sh
- ## Updater für die user.js von Privacy-Handbuch.de
- ## Version: 1.6.2
- ## by: TotallyLeGIT
- ## based on the ghacks user.js updater by:
- ## Author: Pat Johnson (@overdodactyl)
- ## Additional contributors: @earthlng, @ema-pe, @claustromaniac
- ## Dependencies: ·curl or wget
- #########################
- # Misc/Helper Functions #
- #########################
- # Set variables based on the operating system reported by uname.
- abstract_os() {
- if [ "$(uname)" = 'Darwin' ]; then
- readonly open_command='open'
- readonly ff_dir="${HOME}/Library/Application Support/Firefox"
- readonly ff_file_path="${ff_dir}/profiles.ini"
- readonly global_override_path="${global_override_path:-${ff_dir}/global-user-overrides.js}"
- readonly tb_file_path="${HOME}/Library/Thunderbird/profiles.ini"
- readonly ff_exec_dir='/Applications/Firefox.app/Contents/MacOS/'
- readonly sed_compat_os_script='s/Resources$/MacOS/'
- else
- readonly open_command='xdg-open'
- readonly ff_dir="${HOME}/.mozilla/firefox"
- readonly ff_file_path="${ff_dir}/profiles.ini"
- readonly global_override_path="${global_override_path:-${ff_dir}/global-user-overrides.js}"
- readonly tb_file_path="${HOME}/.thunderbird/profiles.ini"
- readonly ff_exec_dir=''
- readonly sed_compat_os_script=''
- fi
- # set effective path for each profile.ini
- [ -f "${ff_file_path}" ] && ff_file="${ff_file_path}" || ff_file=''
- [ -f "${tb_file_path}" ] && tb_file="${tb_file_path}" || tb_file=''
- readonly ff_file tb_file
- }
- err_exit() {
- printv '3' '%s\n' "${color_err}[Error] ${*}${color_neutral_stderr}" 1>&2
- exit 1
- }
- err_help_exit() {
- printf '%s\n' "${color_err}[Error] ${*}${color_neutral_stderr}" 1>&2
- printf "Use '-h' option for more information.\n" 1>&2
- exit 1
- }
- print_global_overrides() {
- [ ! -e "${global_override_path}" ] && return 0
- printv_info '0' 'global overrides' "${global_override_path}"
- }
- print_warn() {
- printv '2' '%s\n' "${color_warn}[Warning] ${*}${color_neutral_stderr}" 1>&2
- }
- # Print if message is more important than the quiescence specified.
- # $1: importance (should be a non-negative integer)
- # $2: printf format string
- # $3: string to print (only one)
- printv() {
- # shellcheck disable=SC2059
- [ "${1}" -ge "${quiescence}" ] && printf "${2}" "${3}" || return 0
- }
- # Format and print informational text to terminal.
- # $1 : importance (should be a non-negative integer)
- # $2 : information label
- # $3…: information (all arguments >= 3)
- printv_info() {
- importance="${1}"
- shift
- printv "${importance}" '%-19s' "${1}:"
- shift
- printv "${importance}" '%s\n' "${color_info}${*}${no_color_stdout}"
- }
- # See 'extract_version', but without Thunderbird.
- extract_ff_version() {
- if ! ff_version_output="$("${1}"firefox --version 2>/dev/null)"; then
- return 1
- elif printf '%s' "${ff_version_output}" | grep -q 'esr'; then
- ff_version_extracted="Firefox ESR $(printf '%s' "${ff_version_output}" \
- | cut -d ' ' -f 3 | cut -d '.' -f 1)"
- else
- ff_version_extracted='Firefox release'
- fi
- printf '%s' "${ff_version_extracted}"
- }
- # Determine if a given directory contains Thunderbird or Firefox.
- # Print 'Firefox ESR XY' (XY being the major version number), 'Firefox release'
- # or 'Thunderbird'. Return 1 if none found.
- # $1: directory of executable (CAUTION: append a trailing / )
- # If no argument is given, executables are searched for in $PATH.
- extract_version() {
- if [ -f "${1}thunderbird" ] && [ -x "${1}thunderbird" ]; then
- printf 'Thunderbird'
- return 0
- else
- extract_ff_version "${1}"
- fi
- }
- # Parse command line options and set variables accordingly.
- parse_options() {
- if [ "${#}" -ne 0 ]; then
- # display usage if first argument contains -help
- if printf '%s' "${1}" | grep -qi '\-help'; then
- usage
- exit 0
- else
- while getopts ':abc:de:g:hilno:p:qrstuvy' opt; do
- case "${opt}" in
- a)
- profile_path_option='all'
- ;;
- b)
- backup_multiple='false'
- ;;
- c)
- if ! config_wanted_global="$(printf '%s' "${OPTARG}" \
- | tr '[:upper:]' '[:lower:]' \
- | awk '{print $1; exit}' \
- | grep '^arkenfox$\|^minimal$\|^moderat$\|^medium$\|^streng$\|^hotspot$\|^empty$\|^horlogeskynet$\|^tb$\|^tb-streng$')"
- then
- err_help_exit "Invalid CONFIG: '${OPTARG}'"
- fi
- ;;
- d)
- compare='true'
- ;;
- e)
- if ff_version_wanted_global="$(printf '%s' "${OPTARG}" \
- | awk '{print $1; exit}' \
- | grep '^[[:digit:]]*$')"
- then
- ff_version_specified='true'
- else
- err_help_exit 'VERSION must be an integer'
- fi
- ;;
- g)
- [ ! -e "${OPTARG}" ] && err_exit "'${OPTARG}': not found"
- global_override_path="${OPTARG}"
- ;;
- h)
- usage
- exit 0
- ;;
- i)
- view='true'
- ;;
- l)
- profile_path_option='list'
- ;;
- n)
- override='false'
- ;;
- o)
- override='true'
- override_path="${OPTARG}"
- ;;
- p)
- update_profile_path "${OPTARG}"
- [ "${profile_path_option}" = 'false' ] && profile_path_option='true'
- ;;
- q)
- quiescence="$((quiescence+1))"
- ;;
- r)
- just_read='true'
- ;;
- # TODO: remove '-s' in future version
- s|u)
- update='true'
- ;;
- t)
- confirm='no'
- dry_run='true'
- ;;
- v)
- printf '%s\n' "PH-userjs-updater ${version}"
- exit 0
- ;;
- y)
- confirm='no'
- ;;
- \?)
- err_help_exit "Invalid option: '${OPTARG}'"
- ;;
- :)
- err_help_exit "Option requires an argument: '${OPTARG}'"
- ;;
- esac
- done
- fi
- fi
- }
- # Initialize misc stuff.
- # $1: this script's name (usually $0)
- prepare() {
- tmp_dir="$(mktemp -dt userjs.XXXXXX)"
- readonly tmp_dir
- trap 'exit 130' INT HUP QUIT TERM ALRM
- # shellcheck disable=SC2154
- trap 'rc="${?}"; rm -rf "${tmp_dir}"; exit "${rc}"' EXIT
- script_path="$(readlink -f "${1}" 2>/dev/null \
- || greadlink -f "${1}" 2>/dev/null || printf '%s' "${1}")"
- readonly script_path
- # Download method priority: curl > wget
- if command -v curl >/dev/null; then
- readonly download_command='curl --location --max-redirs 2 --max-time 30 --fail --silent --output'
- elif command -v wget >/dev/null; then
- # -O file = --output-document=file
- readonly download_command='wget --max-redirect=2 --timeout=30 --quiet -O'
- else
- err_exit 'This script requires curl or wget'
- fi
- }
- # Determine Firefox (FF) update channel and set $ff_version_wanted_global
- # accordingly: major version number for FF esr (e. g. 91) or 0 for FF release
- set_ff_version_wanted_global() {
- if [ "${ff_version_specified}" = 'false' ]; then
- if ! ff_version_wanted_global="$(extract_ff_version "${ff_exec_dir}")"; then
- ff_version_wanted_global='none'
- fi
- else
- if [ "${ff_version_wanted_global}" -eq 0 ]; then
- ff_version_wanted_global='Firefox release'
- else
- esr_to_dl="ff${ff_version_wanted_global}"
- ff_version_wanted_global="Firefox ESR ${ff_version_wanted_global}"
- fi
- fi
- readonly ff_version_wanted_global
- printv_info '0' 'default browser' "${ff_version_wanted_global}"
- }
- # Initialize variables needed for parse_options().
- set_variables() {
- # Colors used for printing only when stdout is a terminal
- if [ -t 1 ]; then
- # green
- color_info="$(tput setaf 2)"
- # blue
- color_usage="$(tput setaf 4)"
- # blue, bold
- color_user_input="$(tput setaf 4)$(tput bold)"
- no_color_stdout="$(tput sgr0)"
- else
- color_info=''
- color_usage=''
- color_user_input=''
- no_color_stdout=''
- fi
- if [ -t 2 ]; then
- # red
- color_err="$(tput setaf 1)"
- # yellow (orange-ish)
- color_warn="$(tput setaf 3)"
- color_neutral_stderr="$(tput sgr0)"
- else
- color_err=''
- color_warn=''
- color_neutral_stderr=''
- fi
- readonly color_info color_usage color_user_input no_color_stdout
- readonly color_err color_warn color_neutral_stderr
- # Argument defaults
- backup_multiple='true'
- compare='false'
- compat_file='compatibility.ini'
- config_wanted_global='keep'
- confirm='yes'
- dry_run='false'
- ff_version_specified='false'
- just_read='false'
- # soft: look for user-overrides.js but only give info when none found
- override='soft'
- override_path='user-overrides.js'
- profile_path=''
- profile_path_option='false'
- pwd_start="$(pwd)"
- quiescence=0
- update='false'
- view='false'
- # constants
- readonly backup_dir='userjs_backups'
- readonly diff_dir='userjs_diffs'
- # TODO: remove version comment in line 4 in v2.0
- readonly version='1.6.2'
- }
- usage() {
- printf '%s' "${color_usage}userjs-updater${no_color_stdout}
- Updater: ${color_usage}https://notabug.org/TotallyLeGIT/PH-userjs-updater${no_color_stdout}
- Firefox user.js: ${color_usage}https://www.privacy-handbuch.de/handbuch_21u.htm
- https://github.com/arkenfox/user.js${no_color_stdout}
- Thunderbird user.js: ${color_usage}https://www.privacy-handbuch.de/handbuch_31p.htm
- https://github.com/HorlogeSkynet/thunderbird-user.js${no_color_stdout}
- ${color_usage}Usage: ${0} [-abdghilnruvy] [-c CONFIG] [-e VERSION] [-o OVERRIDE] [-p PROFILE]${no_color_stdout}
- -a Update all Firefox and Thunderbird profiles at once while keeping
- CONFIGs the same. Profiles without a user.js will be skipped.
- -b Only keep one user.js backup and one diff file.
- -c CONFIG Specify the Firefox user.js config you want: arkenfox, minimal, moderat, medium
- (= medium streng), streng (= sehr streng), hotspot or empty
- For Thunderbird: HorlogeSkynet, tb or tb-streng
- Empty creates a user.js containing just one commented line so that (global)
- overrides will be apllied to this profile.
- This option is only needed if you want to change to another config.
- Note that this option will always have effect on all selected profiles.
- -d Create a diff file comparing old and new user.js within ${diff_dir} subdirectory.
- -e VERSION Force download of user.js for Firefox ESR with version number VERSION for all
- profiles. Make sure the user.js for this version actually exists.
- Example: '-e 91' will download the user.js for Firefox ESR Version 91.x .
- Use '-e 0' to force the download of the user.js for the release update channel.
- Precedence to find Firefox update channel:
- -e > previous user.js > compatibility.ini > 'firefox --version'
- -g OVERRIDE Path to global overrides. These overrides get appended to every Firefox user.js, but
- not to unmanaged profiles (see '-c empty'). Per-profile overrides take precedence
- over these global ones. OVERRIDE may be a directory – see '-o'.
- The default path will always be applied, if present, even without this option:
- ~/.mozilla/firefox/global-user-overrides.js (Linux)
- ~/Library/Application Support/Firefox/global-user-overrides.js (MacOS)
- -h Show this help message and exit.
- -i Inspect the resulting user.js file.
- -l Interactively choose your profile from a list.
- -n Do not append any overrides even if user-overrides.js exists.
- -o OVERRIDE Filename or path to overrides file, needed if different than PROFILE/user-overrides.js .
- If used with -p, the path may be relative to PROFILE or an absolute path.
- If given a directory, all files inside ending in .js will be appended.
- -p PROFILE Path to your profile directory, needed if different than this script's location.
- May be used multiple times.
- IMPORTANT: If the profile path includes spaces, wrap whole path in quotes.
- -q Be quieter. Use multiple times to show less output: additional information,
- all information, warnings, errors will be silenced in this order. When completely
- silent, the outcome is still represented by the exit code.
- -r Only download user.js to a temporary file and open it. This requires -c .
- -s (Deprecated) This is an alias for -u .
- -t Dry-run: Perform a trial run that doesn't change anything and produces mostly
- the same output. Implies -y .
- -u Check for updates of this updater and install if available.
- -v Display updater version and exit.
- -y Update user.js without confirmation.
- "
- }
- #########################
- # (Pro)File Handling #
- #########################
- # Download a resource.
- # $1: the file name, where the resource will be saved to
- # $2: URL of the resource to download
- # Return: 1 on error, else 0
- download_file() {
- if [ "${2}" = 'empty' ]; then
- # This string makes parsing easy as it looks similar to a normal user.js.
- printf '// user_pref("_user.js.prhdb", "empty");\n' > "${1}" || return 1
- else
- ${download_command} "${1}" "${2}" || return 1
- fi
- }
- # Update $profile_path (especially with list/-l) or exit on error.
- get_profile_path() {
- if [ "${profile_path_option}" = 'list' ]; then
- if [ -n "${ff_file}" ]; then
- ini="${ff_file}"
- [ -n "${tb_file}" ] && ini='both' || printf 'Firefox detected.\n\n'
- elif [ -n "${tb_file}" ]; then
- ini="${tb_file}"
- printf 'Thunderbird detected.\n\n'
- else
- err_exit "Neither Thunderbird nor Firefox could be found, or '-l' is" \
- "not supported on your OS. Try '-p' option"
- fi
- if [ "${ini}" = 'both' ]; then
- while [ -z "${reply}" ]; do
- printf '%s' "${color_user_input}(F)irefox and (T)hunderbird were"
- printf '%s' " detected. Select one: f,t?${no_color_stdout} "
- read -r reply
- done
- reply="$(printf '%s' "${reply}" | tr '[:upper:]' '[:lower:]')"
- if [ -z "${reply##f*}" ]; then
- printf 'Firefox was selected.\n\n'
- read_ini_file "${ff_file}"
- elif [ -z "${reply##t*}" ]; then
- printf 'Thunderbird was selected.\n\n'
- read_ini_file "${tb_file}"
- else
- err_exit 'Could not parse your input'
- fi
- fi
- elif [ "${profile_path_option}" = 'all' ]; then
- for file in "${ff_file}" "${tb_file}"; do
- if [ -f "${file}" ]; then
- profile_path_temp="$(sed -ne 's/^Path=\(.*\)$/\1/p' "${file}")"
- else
- continue
- fi
- while read -r line; do
- if ! printf '%s' "${line}" | grep -q '^/'; then
- profile_path_to_update="${file%profiles.ini}${line}"
- else
- profile_path_to_update="${line}"
- fi
- update_profile_path "${profile_path_to_update}"
- # we don't want a subshell here
- done <<EOF
- ${profile_path_temp}
- EOF
- done
- elif [ "${profile_path_option}" = 'false' ]; then
- possible_userjs_dir="$(dirname "${script_path}")"
- # user.js in current working directory?
- if [ -e 'user.js' ] || [ -e "${compat_file}" ] || [ -e 'times.json' ]; then
- update_profile_path "$(pwd)"
- # user.js in same directory as script?
- elif [ -e "${possible_userjs_dir}/user.js" ]; then
- update_profile_path "${possible_userjs_dir}"
- else
- err_exit "Could not detect user.js location. Use '-p PROFILE'"
- fi
- fi
- if [ -z "${profile_path}" ]; then
- err_exit 'No valid profile path found'
- fi
- readonly profile_path
- }
- # Download user.js and put it to given path. Note the variables that should be
- # set for get_userjs_link(). Requires $profile_path_option to be set.
- # $1: path where the user.js should be saved
- # $2: set to 'true' to indicate a Firefox profile, otherwise no global
- # overrides will be appended
- get_userjs() {
- if [ ! -f "${1}" ]; then
- link="$(get_userjs_link)"
- if ! download_file "${1}" "${link}"; then
- if [ "${profile_path_option}" = 'all' ]; then
- print_warn 'Download of new user.js failed'
- return 1
- else
- err_exit 'Download of new user.js failed'
- fi
- fi
- [ "${2}" = 'true' ] && add_global_overrides "${1}"
- fi
- if ! new_version_long="$(get_userjs_version "${new_userjs}")"; then
- err_exit 'Could not parse new user.js'
- fi
- printv_info '0' ' new user.js' "${new_version_long}"
- }
- # Open a file for the user to view.
- # $1: path to file
- open_file() {
- "${open_command}" "${1}" || err_exit 'Cannot open files on your OS'
- }
- # Parse profiles.ini to find the correct profile for the user.js.
- # $1: absolute path of profiles.ini
- read_ini_file() {
- readonly ini_file="${1}"
- # only 1 profile found
- if [ "$(grep -c '^\[Profile' "${ini_file}")" -eq 1 ]; then
- ini_content="$(grep '^\[Profile' -A 4 "${ini_file}")"
- # more than 1 profile
- else
- printf 'Profiles found:\n'
- printf '————————————————————————————————————————————\n'
- grep -E 'Default=[^1]|\[Profile[0-9]*\]|Name=|Path=|^$' "${ini_file}"
- printf '————————————————————————————————————————————\n'
- printf '%s' "${color_user_input}Select the profile number"
- printf '%s' " (Profile(0), Profile(1) etc.): 1,2,…?${no_color_stdout} "
- read -r reply
- printf '\n'
- ini_content="$(grep '^\[Profile'"${reply}" -A 4 "${ini_file}")" \
- || err_exit "Profile${reply} does not exist"
- fi
- profile_path_to_add="$(printf '%s' "${ini_content}" \
- | sed -n 's/^Path=\(.*\)$/\1/p')"
- path_is_rel="$(printf '%s' "${ini_content}" \
- | sed -n 's/^IsRelative=\([01]\)$/\1/p')"
- # update global variable if path is relative
- [ "${path_is_rel}" -eq 1 ] \
- && profile_path_to_add="$(dirname "${ini_file}")/${profile_path_to_add}"
- update_profile_path "${profile_path_to_add}"
- }
- # Add a path to the list of profile paths, separated by newlines.
- # $1: one profile path
- update_profile_path() {
- if [ ! -d "${1}" ]; then
- print_warn "Invalid profile path: '${1}'"
- return 1
- fi
- if [ -e "${1}/user.js" ] && [ ! -w "${1}/user.js" ]; then
- print_warn "No permission to write file: '${1}/user.js'"
- return 1
- fi
- # if profile path empty, set variable to path
- if [ -z "${profile_path}" ]; then
- profile_path="${1}"
- # else append profile path
- else
- profile_path="$(printf '%s\n%s' "${profile_path}" "${1}")"
- fi
- }
- #########################
- # Update Updater #
- #########################
- # Update this updater. Call this function with "$@" as argument.
- update_updater() {
- # update check has not been activated
- [ "${update}" = 'false' ] && return 0
- readonly new_updater="${tmp_dir}/new_updater"
- if ! download_file "${new_updater}" \
- 'https://notabug.org/TotallyLeGIT/PH-userjs-updater/raw/main/updater'
- then
- print_warn 'Download of new updater failed'
- return 1
- fi
- chmod u+x "${new_updater}"
- current_updater_version="$("${script_path}" -v | cut -d ' ' -f 2)"
- new_updater_version="$("${new_updater}" -v | cut -d ' ' -f 2)"
- # compare updater versions, if different
- while [ "${current_updater_version}" != "${new_updater_version}" ]; do
- difference="$((${new_updater_version%%.*}-${current_updater_version%%.*}))"
- # newer version available
- if [ "${difference}" -gt 0 ]; then
- printv_info '0' 'updater' 'update available'
- # apply update
- if ! { cat "${new_updater}" > "${script_path}" ; } > /dev/null 2>&1; then
- print_warn "No permission to write file: '${script_path}'"
- return 1
- fi
- printv_info '1' 'changelog' \
- 'https://notabug.org/TotallyLeGIT/PH-userjs-updater/raw/main/CHANGELOG.md'
- # update user.js with new version
- "${script_path}" "${@}"
- # exit with exit code from updater call above
- exit "${?}"
- # version number is equal (go to next number)
- elif [ "${difference}" -eq 0 ]; then
- current_updater_version="${current_updater_version#*.}"
- new_updater_version="${new_updater_version#*.}"
- # this should not be happening
- else
- print_warn 'Your updater version seems odd. Check updater homepage' \
- 'and/or update manually.'
- return 2
- fi
- done
- printv_info '0' 'updater' 'up to date'
- }
- #########################
- # Update user.js #
- #########################
- # Add global overrides to a user.js.
- # $1: Path to a file which the overrides should be appended to
- add_global_overrides() {
- [ ! -e "${global_override_path}" ] && return 0
- printf '\n\n// global user-overrides\n' >> "${1}"
- append_overrides_content "${global_override_path}" "${1}" '1'
- }
- # Add local overrides to a user.js. Acts on a user.js whose path must be
- # stored in the variable $new_userjs which is changed if there are overrides.
- add_profile_overrides() {
- { [ "${override}" = 'false' ] || [ ! -e "${override_path}" ] ; } && return 0
- new_userjs_tmp="${new_userjs}_$(basename "${PWD}")"
- cp "${new_userjs}" "${new_userjs_tmp}"
- new_userjs="${new_userjs_tmp}"
- printf '\n\n// user-overrides\n' >> "${new_userjs}"
- append_overrides_content "${override_path}" "${new_userjs}"
- }
- # Append given override file or all files suffixed .js in given directory.
- # $1: Path to overrides
- # $2: Path to a file to append the overrides to
- # $3: Set to anything different than empty or 0 to indicate global overrides
- append_overrides_content() {
- input="${1}"
- output="${2}"
- if [ -f "${input}" ]; then
- printf '\n' >> "${output}"
- cat "${input}" >> "${output}"
- [ "${3:-0}" = 0 ] && printv_info '0' 'profile overrides' "${input}"
- elif [ -d "${input}" ]; then
- files="$(find "${input}" -mindepth 1 -maxdepth 1 -type f -name '*.js')"
- if [ -z "${files}" ]; then
- print_warn "No .js file in directory: '${input}'"
- return 1
- else
- printf '%s\n' "${files}" \
- | while read -r f
- do
- append_overrides_content "${f}" "${output}" "${3}"
- done
- fi
- else
- if [ "${override}" = 'soft' ]; then
- printv_info '0' 'profile overrides' 'none found'
- else
- print_warn "Invalid overrides path: '${input}'"
- return 1
- fi
- fi
- }
- # Perform checks whether the user.js to be downloaded seems sane given a
- # specific profile (profile = current working dir) and warn if not.
- check_userjs_against_profile() {
- unset print_warning
- [ -z "${version_profile_compat}" ] && return 0
- if [ "${ff_version_wanted_global}" != "${version_profile_compat}" ]
- then
- printv_info '0' 'profile used by' "${version_profile_compat}"
- fi
- # Thunderbird
- if [ -z "${is_config_wanted_profile_ff}" ]; then
- if [ "${version_profile_compat%% *}" = 'Firefox' ]; then
- print_warning='true'
- fi
- # Firefox
- else
- if [ "${version_profile_compat}" = 'Thunderbird' ]; then
- print_warning='true'
- # Firefox update channels do not match
- elif [ "${version_profile_compat#Firefox release}" != "$(printf \
- '%s' "${esr_to_dl}" | sed 's/ff/Firefox ESR /')" ]
- then
- print_warning='true'
- fi
- fi
- }
- # Return a user.js download link. Variables used here must be set beforehand.
- get_userjs_link() {
- case "${config_wanted_profile}" in
- empty)
- printf 'empty'
- return ;;
- arkenfox)
- printf 'https://raw.githubusercontent.com/arkenfox/user.js/master/user.js'
- return ;;
- HorlogeSkynet|horlogeskynet)
- printf 'https://raw.githubusercontent.com/HorlogeSkynet/thunderbird-user.js/master/user.js'
- return ;;
- esac
- printf '%s' "https://www.privacy-handbuch.de/download/"
- if [ -n "${is_config_wanted_profile_ff}" ]; then
- printf '%s' "${esr_to_dl:+$esr_to_dl/}"
- fi
- printf '%s' "${config_wanted_profile}/user.js"
- }
- # Print the version of a PH user.js file or return 1 if no user.js present.
- get_userjs_version() {
- [ -f "${1}" ] && userjs_version="$(grep -m1 \
- '_user\.js\.prhdb\|https://github\.com/\(arkenfox/\|HorlogeSkynet/thunderbird-\)user\.js' "${1}" \
- | sed -ne '/arkenfox/ s/.*/arkenfox/p' \
- -e '/HorlogeSkynet/ s/.*/HorlogeSkynet/p' \
- -e '/prhdb/ s/^[^"]*"[^"]*"[^"]*"\([^"]*\)"[^"]*$/\1/p')"
- [ -z "${userjs_version}" ] && return 1
- printf '%s' "${userjs_version}"
- }
- # Set $version_profile_compat to Thunderbird/Firefox version. Executable path
- # is taken from $compat_file. Current working directory needs to be the profile.
- #
- # Return: 1 if $compat_file doesn't exist or on error, else 0.
- get_version_compat() {
- if [ -e "${compat_file}" ]; then
- exec_dir_profile="$(sed \
- -ne 's/^LastPlatformDir=\([[:graph:]]*\)$/\1/p' "${compat_file}" \
- | sed -e "${sed_compat_os_script}")"
- if version_profile_compat="$(extract_version "${exec_dir_profile}/")"; then
- printf '%s' "${version_profile_compat}"
- return 0
- fi
- fi
- return 1
- }
- # Download a user.js, open it and exit.
- read_and_exit() {
- [ "${just_read}" = 'false' ] && return 0
- if ! set_config_wanted_profile; then
- err_exit "Could not determine which CONFIG to download. Use '-c CONFIG'"
- fi
- set_esr_to_dl
- userjs_tmp="$(mktemp -dt userjs.XXXXXX)/${esr_to_dl}${config_wanted_profile}"
- if ! download_file "${userjs_tmp}" "$(get_userjs_link)"; then
- err_exit 'Download of new user.js failed'
- fi
- printv_info '0' 'user.js saved to' "${userjs_tmp}"
- open_file "${userjs_tmp}"
- exit 0
- }
- # Set $config_wanted_profile to the CONFIG the user wants for this profile.
- set_config_wanted_profile() {
- unset is_config_wanted_profile_ff
- # 'keep' means to try autodetection
- if [ "${config_wanted_global}" = 'keep' ]; then
- # config detection impossible
- [ -z "${current_userjs_version_long}" ] && return 1
- config_wanted_profile="${current_userjs_version_long%_*}"
- # will be e. g. 'streng' or empty afterwards
- config_wanted_profile="${config_wanted_profile#*_}"
- # TODO: remove %2 in future version (tb2 leftover)
- config_wanted_profile="${config_wanted_profile%2}"
- else
- config_wanted_profile="${config_wanted_global}"
- fi
- if [ "${config_wanted_profile%-streng}" != 'tb' ]; then
- is_config_wanted_profile_ff='true'
- fi
- }
- # Set $esr_to_dl to something like 'ff91' or empty
- set_esr_to_dl() {
- # don't waste time if already globally forced by user
- [ "${ff_version_specified}" = 'true' ] && return 0
- unset esr_to_dl
- [ -z "${is_config_wanted_profile_ff}" ] && return 0
- if [ -n "${current_userjs_version_long}" ] \
- && [ -n "${current_userjs_version_long%%tb*}" ]
- then
- esr_to_dl="$(printf '%s' "${current_userjs_version_long}" \
- | sed -ne 's/\(ff[[:digit:]]*\)_.*/\1/p')"
- elif [ "${version_profile_compat%% *}" = 'Firefox' ]; then
- if [ "${version_profile_compat% *}" = 'Firefox ESR' ]; then
- esr_to_dl="ff${version_profile_compat##* }"
- fi
- elif [ "${ff_version_wanted_global%% *}" = 'Firefox' ]; then
- if [ "${ff_version_wanted_global% *}" = 'Firefox ESR' ]; then
- esr_to_dl="ff${ff_version_wanted_global##* }"
- fi
- # Could not find any update channel
- else
- err_exit "Could not determine Firefox update channel. Use '-e VERSION'"
- fi
- }
- # Apply chosen version of user.js and any custom overrides.
- update_userjs() {
- current_userjs_version_long="$(get_userjs_version 'user.js')"
- printv_info '1' 'profile path' "${PWD}"
- if ! set_config_wanted_profile; then
- if [ "${profile_path_option}" = 'all' ]; then
- printv_info '1' 'user.js status' 'none found – skipped'
- return 1
- else
- err_exit 'Could not determine which CONFIG to download. Use' \
- "'-c CONFIG' and/or '-p PROFILE'"
- fi
- fi
- version_profile_compat="$(get_version_compat)"
- set_esr_to_dl
- check_userjs_against_profile
- printv_info '0' 'current user.js' "${current_userjs_version_long:-not detected}"
- new_userjs="${tmp_dir}/userjs_${is_config_wanted_profile_ff:+$esr_to_dl}${config_wanted_profile}"
- get_userjs "${new_userjs}" "${is_config_wanted_profile_ff}" || return 1
- # if `check_userjs_against_profile` found something
- if [ -n "${print_warning}" ]; then
- print_warn "It seems the user.js won't fit this profile. Please" \
- 'recheck your configuration.'
- fi
- add_profile_overrides
- # Inspect (-i). If the user.js is identical, this script exits and deletes
- # the temporary user.js faster than open_file calling xdg-open opens it, so
- # it opens an already deleted, thus empty file. Sleep works around this.
- # It shouldn't be too bad, as the editor is opened in foreground anyway and
- # -i is probably not used a lot – not in a fast update run anyway.
- [ "${view}" = 'true' ] && open_file "${new_userjs}" && sleep 0.5
- # files are identical
- if cmp -s "${new_userjs}" 'user.js'; then
- printv_info '1' 'user.js status' 'identical – skipped'
- return 0
- fi
- if [ "${confirm}" = 'yes' ]; then
- printf '\n%s' "${color_user_input}Update user.js?"
- printf '\n%s' "(y)es / (n)o: Y,n?${no_color_stdout} "
- IFS='' read -r reply </dev/tty
- # y, j or empty → comfirmation
- if printf '%s' "${reply}" | grep -vq '^[yYjJ]*$'; then
- printf '%s\n' "${color_info}skipping profile${no_color_stdout}"
- return 1
- fi
- fi
- if [ -f 'user.js' ]; then
- status_output='backed up and updated'
- else
- status_output='installed'
- fi
- if [ "${dry_run}" = 'false' ]; then
- # create diff
- [ "${backup_multiple}" = 'true' ] && date_file="$(date '+%FT%T')_" \
- || date_file=''
- if [ "${compare}" = 'true' ]; then
- mkdir -p "${diff_dir}"
- diff -wBU 0 'user.js' "${new_userjs}" > "${diff_dir}/${date_file}diff.txt"
- printv_info '0' 'diff status' 'diff file created'
- fi
- # backup user.js
- mkdir -p "${backup_dir}"
- backup_file="${backup_dir}/${date_file}user.js"
- [ -f 'user.js' ] && cp -p 'user.js' "${backup_file}"
- # install newest user.js
- cat "${new_userjs}" > 'user.js'
- dry_run_output=''
- else
- dry_run_output=' (DRY-RUN)'
- fi
- printv_info '1' 'user.js status' "${status_output}${dry_run_output}"
- return 0
- }
- #########################
- # Main() #
- #########################
- set_variables
- parse_options "${@}"
- prepare "${0}"
- update_updater "${@}"
- abstract_os
- set_ff_version_wanted_global
- read_and_exit
- print_global_overrides
- get_profile_path
- while read -r line; do
- printv '0' '————————————————————————————————————————————\n'
- # this enables us to leave relative profile paths as they are
- { cd "${pwd_start}" && cd "${line}" ; } || exit 99
- update_userjs
- done <<EOF
- ${profile_path}
- EOF
- # vim: shiftwidth=2 tabstop=2 noexpandtab
|