123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- #!/bin/sh
- ## Updater für die user.js von Privacy-Handbuch.de
- ## Version: 1.3.0
- ## by: TotallyLeGIT
- ## based on the ghacks user.js updater by:
- ## Author: Pat Johnson (@overdodactyl)
- ## Additional contributors: @earthlng, @ema-pe, @claustromaniac
- ## Dependencies: ·curl or wget
- scriptLocation="$(readlink -f "${0}" 2>/dev/null || greadlink -f "${0}" 2>/dev/null || printf "%s" "${0}")"
- readonly scriptLocation
- #########################
- # Base variables #
- #########################
- # Colors used for printing only when stdout is a terminal
- if [ -t 1 ]; then
- red="$(tput setaf 1)$(tput bold)"
- blue="$(tput setaf 4)"
- green="$(tput setaf 2)"
- yellow="$(tput setaf 3)"
- neutral="$(tput sgr0)" # No Color
- else
- red=""
- blue=""
- green=""
- yellow=""
- neutral=""
- fi
- # Argument defaults
- BACKUP='multiple'
- COMPARE=false
- configWanted='keep'
- CONFIRM='yes'
- esr=0
- OVERRIDE="soft" # soft: look for user-overrides.js but only give info when none found
- overridePath='user-overrides.js'
- profilePathOption=false
- VIEW=false
- UPDATE='no'
- readonly backupsDir="userjs_backups"
- readonly diffsDir="userjs_diffs"
- # Download method priority: curl → wget
- if command -v curl >/dev/null; then
- DOWNLOAD_COMMAND='curl --max-redirs 2 --max-time 30 --fail --silent --output'
- elif command -v wget >/dev/null; then
- # -O file = --output-document=file
- DOWNLOAD_COMMAND='wget --max-redirect=2 --timeout=30 --quiet -O'
- else
- echo "${red}This script requires curl or wget."
- echo "Process aborted.${neutral}"
- exit 2
- fi
- show_banner () {
- echo "${blue}
- #########################################################################
- #### Updater for Privacy-Handbuch's user.js ####
- #### Suitable for both Firefox and Thunderbird ####
- #########################################################################${neutral}
- Updater: ${blue}https://notabug.org/TotallyLeGIT/PH-userjs-updater${neutral}
- Firefox user.js: ${blue}https://www.privacy-handbuch.de/handbuch_21u.htm${neutral}
- Thunderbird user.js: ${blue}https://www.privacy-handbuch.de/handbuch_31p.htm${neutral}
- "
- }
- #########################
- # Arguments #
- #########################
- usage() {
- show_banner
- echo
- echo "${blue}Usage: ${0} [-bdhilnrsuy] [-c CONFIG] [-e VERSION] [-o OVERRIDE] [-p PROFILE]${neutral}" 1>&2 # Echo usage string to standard error
- echo "
- -b Only keep one user.js backup and one diff file.
- -c CONFIG Specify the Firefox user.js config you want: minimal, moderat, streng or hotspot
- or for Thunderbird: tb or tb2 .
- This is only needed if you want to change to another config.
- -d Create a diff file comparing old and new user.js within ${diffsDir} subdirectory.
- -e VERSION Force download of user.js for Firefox ESR with version number VERSION.
- Example: \"-e 91\" will download the user.js for Firefox ESR Version 91.x .
- -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.
- -r Only download user.js to a temporary file and open it. This requires -c.
- -s Check for updates of this updater and update silently without confirmation.
- -u Check for updates of this updater and ask for confirmation if update available.
- -y Update user.js without confirmation.
- "
- }
- #########################
- # (Pro)File Handling #
- #########################
- abstract_OS () {
- if [ "$(uname)" = 'Darwin' ]; then
- readonly open_command='open'
- readonly version_command='/Applications/Firefox.app/Contents/MacOS/firefox --version'
- readonly ff_file_path="${HOME}/Library/Application Support/Firefox/profiles.ini"
- readonly tb_file_path="${HOME}/Library/Thunderbird/profiles.ini"
- else
- readonly open_command='xdg-open'
- readonly version_command='firefox --version'
- readonly ff_file_path="${HOME}/.mozilla/firefox/profiles.ini"
- readonly tb_file_path="${HOME}/.thunderbird/profiles.ini"
- fi
- # set effective path for each profile.ini
- [ -f "${ff_file_path}" ] && fffile="${ff_file_path}" || fffile=""
- [ -f "${tb_file_path}" ] && tbfile="${tb_file_path}" || tbfile=""
- readonly fffile tbfile
- }
- # downloads a resource. expects two arguments:
- # $1 the variable name, where the filename will be saved to
- # $2 the resource to download
- # example usage: download_file 'var' 'https://example.com/resource'
- download_file () {
- eval "$1=$(mktemp)"
- if ! eval "${DOWNLOAD_COMMAND} \$${1} ${2}"; then
- echo "${red}Download of resource failed:${neutral} ${2}"
- return 33
- fi
- }
- open_file () { # expects one argument: file_path
- eval "${open_command} ${1}" || echo "${red}Error: Sorry, opening" \
- "files is not supported for your OS.${neutral}"
- }
- readIniFile () { # expects one argument: absolute path of profiles.ini
- readonly inifile="${1}"
- if [ "$(grep -c '^\[Profile' "${inifile}")" -eq 1 ]; then # only 1 profile found
- tempIni="$(grep '^\[Profile' -A 4 "${inifile}")"
- else # more than 1 profile
- echo 'Profiles found:'
- echo '–––––––––––––––––––––––––––––––––––'
- grep --color=never -E 'Default=[^1]|\[Profile[0-9]*\]|Name=|Path=|^$' "${inifile}"
- echo '–––––––––––––––––––––––––––––––––––'
- echo 'Select the profile number ( 0 for Profile0, 1 for Profile1 etc. ):'
- read -r reply
- echo
- tempIni="$(grep '^\[Profile'"${reply}" -A 4 "${inifile}")" || { echo "${red}Profile${reply} does not exist!${neutral}" && exit 1 ; }
- fi
- tempProfilePath="$(echo "${tempIni}" | sed -n 's/^Path=\(.*\)$/\1/p')"
- pathIsRel="$(echo "${tempIni}" | sed -n 's/^IsRelative=\([01]\)$/\1/p')"
- readonly pathIsRel
- # update global variable if path is relative
- [ "${pathIsRel}" -eq 1 ] && tempProfilePath="$(dirname "${inifile}")/${tempProfilePath}"
- updateProfilePath "${tempProfilePath}"
- }
- getProfilePath () {
- if [ "${profilePathOption}" = 'list' ]; then
- if [ -n "${fffile}" ]; then
- ini="${fffile}"
- [ -n "${tbfile}" ] && ini="both" || printf "Firefox detected.\n\n"
- elif [ -n "${tbfile}" ]; then
- ini="${tbfile}"
- printf "Thunderbird detected.\n\n"
- else
- echo "${red}Error: Sorry, Thunderbird and Firefox could not be found or -l is not supported for your OS. Try -p option.${neutral}" && exit 1
- fi
- if [ "${ini}" = "both" ]; then
- echo "(F)irefox and (T)hunderbird were detected. Select one: F/T"
- read -r reply
- reply="$(printf "%s" "${reply}" | tr '[:upper:]' '[:lower:]')"
- { [ -z "${reply##f*}" ] && ini="${fffile}" && printf "Firefox was selected.\n\n" ; } || { [ -z "${reply##t*}" ] && ini="${tbfile}" && printf "Thunderbird was selected.\n\n" ; } || { echo "${red}Error: Sorry, could not parse your input.${neutral}" && exit 1 ; }
- fi
- readIniFile "${ini}" # updates PROFILE_PATH or exits on error
- elif [ "${profilePathOption}" = false ]; then
- PROFILE_PATH="$(dirname "${scriptLocation}")"
- fi
- }
- updateProfilePath () { # expects a profile path as argument
- # if profile path empty: update it
- if [ -z "${PROFILE_PATH}" ]; then
- PROFILE_PATH="${1}"
- # update profilePathOption var so we know there's a profile path
- [ "${profilePathOption}" = "false" ] && profilePathOption="true"
- else # append additional profile path
- PROFILE_PATH="${PROFILE_PATH}\n${1}"
- fi
- }
- #########################
- # Update updater #
- #########################
- # Returns the version number of the updater file in the first argument.
- get_updater_version () {
- sed -n '4 s/.*[[:blank:]]\([0-9]*\.[0-9]*\.[0-9]*\)[[:graph:]]*/\1/p' "${1}"
- }
- # Default: Do not check for updates of the updater at all.
- # Args:
- # -u: Check for update. if available, ask user if they want to update.
- # -s: Check for update, if available, execute without asking.
- update_updater () {
- if [ "${UPDATE}" = 'no' ]; then
- return 0 # Do not to check for updates.
- fi
- download_file 'tmp_updater' \
- 'https://notabug.org/TotallyLeGIT/PH-userjs-updater/raw/main/updater' \
- || return 1
- readonly tmp_updater
- updaterVerOld="$(get_updater_version "${scriptLocation}")"
- updaterVerNew="$(get_updater_version "${tmp_updater}")"
- readonly updaterVerOldConst="${updaterVerOld}"
- # compare updater versions, if different
- while [ ! "${updaterVerOld}" = "${updaterVerNew}" ]; do
- difference="$((${updaterVerNew%%.*}-${updaterVerOld%%.*}))"
- if [ "${difference}" -gt 0 ]; then # newer version available
- if [ "${UPDATE}" = 'yes' ]; then # ask to apply update
- echo "There is a newer version of the updater available. ${red}Update? Y/N${neutral}"
- read -r reply
- echo "${reply}" | grep -qv "^[yY]*$" && return 0 # Update available, but user chooses not to update
- fi
- # apply update, regardless if silent or after "yes"
- mv "${tmp_updater}" "${scriptLocation}"
- chmod u+x "${scriptLocation}"
- echo "Updater successfully updated."
- # show changes for this version to the user
- if download_file 'tmp_changelog' \
- 'https://notabug.org/TotallyLeGIT/PH-userjs-updater/raw/main/CHANGELOG.md'
- then
- readonly tmp_changelog
- echo "${green}Changelog:${neutral}"
- echo
- sed -ne '/^## '"${updaterVerOldConst}"'$/ !p' -e "/${updaterVerOldConst}/ q" "${tmp_changelog}"
- fi
- break
- elif [ "${difference}" -eq 0 ]; then # version number is equal (go to next number)
- updaterVerOld="${updaterVerOld#*.}"
- updaterVerNew="${updaterVerNew#*.}"
- else # this should not be happening
- echo "${red}Error: Something with the version numbers seems funny. Check updater homepage and/or update it manually.${neutral}"
- return 2
- fi
- done
- return 0
- }
- #########################
- # Update user.js #
- #########################
- # returns a user.js download link. expects the current version as argument. e.g.: streng_16022020
- get_userjs_link () {
- configIs="${1%_*}"
- configIs="${configIs#*_}"
- [ "${configWanted}" = "keep" ] && configWanted="${configIs}" && [ "${configIs}" = "Not detected." ] && exit 33
- if [ "${configIs%%2*}" != "tb" ]; then
- [ "${esr}" = "0" ] && esrurl="" || esrurl="ff${esr}/"
- fi
- echo "https://www.privacy-handbuch.de/download/${esrurl}${configWanted}/user.js"
- }
- # Returns version number of a user.js file
- get_userjs_version () {
- [ -e "${1}" ] && returnVer="$(sed -ne '/user\.js\.prhdb/ s/.*"\(\([[:alnum:]]*_\)*[[:alpha:]]*_[[:digit:]]*\)".*/\1/p' -e '10 q' "${1}")"
- #[ -e "${1}" ] && returnVer="$(sed -n '5 s/.*"\([[:alnum:]_]\+[0-9]\+\)".*/\1/p' "${1}")"
- [ -z "${returnVer}" ] && echo "Not detected." && exit 33
- echo "${returnVer}"
- }
- # returns 0 if firefox is release or the major version number if firefox is esr
- is_esr () {
- # result is e. g.: 85.0 or 78.7
- ffver="$(eval "${version_command}" 2>/dev/null | cut -d ' ' -f 3 \
- | cut -d '.' -f -2)" || return 1
- [ "${ffver##*.}" -eq 0 ] && echo "0" || echo "${ffver%%.*}"
- }
- add_override () {
- input="${1}"
- if [ -f "${input}" ]; then
- echo >> user.js
- cat "${input}" >> user.js
- echo "Status: ${green}Override file appended:${neutral} ${input}"
- elif [ -d "${input}" ]; then
- find "${input}" -mindepth 1 -maxdepth 1 -name "*.js" |
- while IFS= read -r f
- do
- add_override "${f}"
- done
- else
- if [ "${OVERRIDE}" = "soft" ]; then
- echo "Info: No override file or directory applied."
- else
- echo "${yellow}Warning: Could not find override file or directory:${neutral} ${input}"
- fi
- fi
- }
- # Applies latest version of user.js and any custom overrides
- update_userjs () {
- currentVerFull="$(get_userjs_version user.js)"
- # if esr wasn't forced, try to detect it
- if [ "${esr}" -eq "0" ]; then
- if esr="$(is_esr)"; then
- [ "${esr}" -eq "0" ] && esrstring="Release" || esrstring="ESR ${esr}"
- else
- esrstring="not found" # likely because 'firefox --version' failed
- fi
- fi
- echo "Firefox version: ${green}${esrstring}${neutral}"
- echo "Profile path: ${green}${PWD}${neutral}"
- echo "Currently using: ${green}${currentVerFull}${neutral}"
- # some error handling while setting variables and telling where it went wrong
- link="$(get_userjs_link "${currentVerFull}")"
- [ "${?}" -eq 33 ] && echo "${red}Error: Could not determine which config to download. Use -c CONFIG and/or -p PROFILE. ${neutral}" && exit 1
- download_file 'tmp_userjs' "${link}" \
- || exit 1
- readonly tmp_userjs
- newVersion="$(get_userjs_version "${tmp_userjs}")"
- [ "${?}" -eq 33 ] && echo "${red}Error parsing new user.js${neutral}" && exit 1
- echo "Available online: ${green}${newVersion}${neutral}"
- echo
- if [ "${CONFIRM}" = 'yes' ]; then
- echo "This script will update to the latest user.js file and append any custom configurations from user-overrides.js. ${red}Continue? Y/N ${neutral}"
- read -r reply </dev/tty
- echo
- echo "${reply}" | grep -qv "^[yY]*$" && echo "${red}Process aborted.${neutral}" && rm "${tmp_userjs}" && return 1
- fi
- # backup user.js
- mkdir -p "${backupsDir}"
- [ "${BACKUP}" = 'single' ] && bakDate="$(date -Iseconds)." || bakDate=""
- bakName="${backupsDir}/${bakDate}user.js"
- [ -f user.js ] && mv user.js "${bakName}"
- # install newest user.js
- mv "${tmp_userjs}" user.js
- echo "Status: ${green}user.js has been backed up and replaced with the latest version!${neutral}"
- # apply overrides
- if [ "${OVERRIDE}" != "false" ]; then
- printf "\n%s\n" "// user-overrides" >> user.js
- add_override "${overridePath}"
- fi
- # create diff
- if [ "${COMPARE}" = true ]; then
- [ "${BACKUP}" = 'single' ] && diffDate="$(date -Iseconds)." || diffDate=""
- diffName="${diffsDir}/${diffDate}diff.txt"
- diffs="$(diff -wBU 0 "${bakName}" user.js)"
- if [ -n "${diffs}" ]; then
- mkdir -p "${diffsDir}"
- echo "${diffs}" > "${diffName}"
- echo "Status: ${green}A diff file was created:${neutral} ${PWD}/${diffName}"
- else
- echo "${yellow}Your new user.js file appears to be identical. No diff file was created.${neutral}"
- fi
- fi
- [ "${VIEW}" = true ] && open_file "${PWD}/user.js"
- }
- #########################
- # Execute #
- #########################
- abstract_OS
- if [ ${#} != 0 ]; then
- firstArg="$(printf '%s' "${1}" | tr '[:upper:]' '[:lower:]')"
- # Display usage if first argument contains -help
- if [ -z "${firstArg##*-help*}" ]; then
- usage
- exit 0
- else
- while getopts ":bc:de:hilno:p:rsuy" opt; do
- case "${opt}" in
- b)
- BACKUP='single'
- ;;
- c)
- if ! configWanted="$(printf "%s" "${OPTARG}" | tr '[:upper:]' '[:lower:]' | grep -om 1 '^minimal\|^moderat\|^streng\|^hotspot\|^tb\|^tb2')"; then
- echo "${red}Error: Invalid CONFIG.${neutral} Valid values are: minimal, moderat, streng, hotspot, tb or tb2"
- exit 1
- fi
- ;;
- d)
- COMPARE=true
- ;;
- e)
- esr="${OPTARG}"
- ;;
- h)
- usage
- exit 0
- ;;
- i)
- VIEW=true
- ;;
- l)
- profilePathOption='list'
- ;;
- n)
- OVERRIDE="false"
- ;;
- o)
- OVERRIDE="true"
- overridePath="${OPTARG}"
- ;;
- p)
- updateProfilePath "${OPTARG}"
- ;;
- r)
- if [ "${configWanted}" = "keep" ]; then
- echo "${red}Error: -r option requires -c option, too.${neutral}"
- exit 1
- else
- download_file 'tmp_read_userjs' \
- "$(get_userjs_link "${configWanted}")" \
- || exit 1
- readonly tmp_read_userjs
- fi
- echo "${green}user.js was saved to temporary file ${tmp_read_userjs}${neutral}"
- open_file "${tmp_read_userjs}"
- exit 0
- ;;
- s)
- UPDATE='silent'
- ;;
- u)
- UPDATE='yes'
- ;;
- y)
- CONFIRM='no'
- ;;
- \?)
- echo
- echo "${red}Error! Invalid option: -${OPTARG}${neutral}" 1>&2
- usage
- exit 2
- ;;
- :)
- echo "${red}Error! Option -${OPTARG} requires an argument.${neutral}" 1>&2
- exit 2
- ;;
- esac
- done
- fi
- fi
- getProfilePath # updates PROFILE_PATH or exits on error
- echo "${PROFILE_PATH}" |
- while read -r path; do
- cd "${path}" || { echo "${red}Error: No profile path found.${neutral}" && exit 1 ; }
- update_userjs
- echo
- done
- update_updater
|