123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- #!/usr/bin/env bash
- ## ghacks-user.js updater for macOS and Linux
- ## version: 2.1
- ## Author: Pat Johnson (@overdodactyl)
- ## Additional contributors: @earthlng, @ema-pe
- ## DON'T GO HIGHER THAN VERSION x.9 !! ( because of ASCII comparison in update_updater() )
- readonly CURRDIR=$(pwd)
- sfp=$(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null || greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null)
- if [ -z "$sfp" ]; then sfp=${BASH_SOURCE[0]}; fi
- readonly SCRIPT_DIR=$(dirname "${sfp}")
- #########################
- # Base variables #
- #########################
- # Colors used for printing
- RED='\033[0;31m'
- BLUE='\033[0;34m'
- BBLUE='\033[1;34m'
- GREEN='\033[0;32m'
- ORANGE='\033[0;33m'
- CYAN='\033[0;36m'
- NC='\033[0m' # No Color
- # Argument defaults
- UPDATE='check'
- CONFIRM='yes'
- OVERRIDE='user-overrides.js'
- BACKUP='multiple'
- COMPARE=false
- SKIPOVERRIDE=false
- VIEW=false
- PROFILE_PATH=false
- # Download method priority: curl -> wget
- DOWNLOAD_METHOD=''
- if [[ $(command -v 'curl') ]]; then
- DOWNLOAD_METHOD='curl'
- elif [[ $(command -v 'wget') ]]; then
- DOWNLOAD_METHOD='wget'
- else
- echo -e "${RED}This script requires curl or wget.\nProcess aborted${NC}"
- exit 0
- fi
- show_banner () {
- echo -e "${BBLUE}\n"
- echo ' ############################################################################'
- echo ' #### ####'
- echo ' #### ghacks user.js ####'
- echo ' #### Hardening the Privacy and Security Settings of Firefox ####'
- echo ' #### Maintained by @Thorin-Oakenpants and @earthlng ####'
- echo ' #### Updater for macOS and Linux by @overdodactyl ####'
- echo ' #### ####'
- echo ' ############################################################################'
- echo -e "${NC}\n"
- echo -e "Documentation for this script is available here: ${CYAN}https://github.com/ghacksuserjs/ghacks-user.js/wiki/3.3-Updater-Scripts${NC}\n"
- }
- #########################
- # Arguments #
- #########################
- usage() {
- echo -e "${BLUE}\nUsage: $0 [-h] [-p PROFILE] [-u] [-d] [-s] [-n] [-b] [-c] [-v] [-r] [-o OVERRIDE]\n${NC}" 1>&2 # Echo usage string to standard error
- echo 'Optional Arguments:'
- echo -e "\t-h,\t\t Show this help message and exit."
- echo -e "\t-p PROFILE,\t Path to your Firefox profile (if different than the dir of this script)"
- echo -e "\t\t\t IMPORTANT: if the path include spaces, wrap the entire argument in quotes."
- echo -e "\t-l, \t\t Choose your Firefox profile from a list"
- echo -e "\t-u,\t\t Update updater.sh and execute silently. Do not seek confirmation."
- echo -e "\t-d,\t\t Do not look for updates to updater.sh."
- echo -e "\t-s,\t\t Silently update user.js. Do not seek confirmation."
- echo -e "\t-b,\t\t Only keep one backup of each file."
- echo -e "\t-c,\t\t Create a diff file comparing old and new user.js within userjs_diffs. "
- echo -e "\t-o OVERRIDE,\t Filename or path to overrides file (if different than user-overrides.js)."
- echo -e "\t\t\t If used with -p, paths should be relative to PROFILE or absolute paths"
- echo -e "\t\t\t If given a directory, all files inside will be appended recursively."
- echo -e "\t\t\t You can pass multiple files or directories by passing a comma separated list."
- echo -e "\t\t\t\t Note: If a directory is given, only files inside ending in the extension .js are appended"
- echo -e "\t\t\t\t IMPORTANT: do not add spaces between files/paths. Ex: -o file1.js,file2.js,dir1"
- echo -e "\t\t\t\t IMPORTANT: if any files/paths include spaces, wrap the entire argument in quotes."
- echo -e "\t\t\t\t\t Ex: -o \"override folder\" "
- echo -e "\t-n,\t\t Do not append any overrides, even if user-overrides.js exists."
- echo -e "\t-v,\t\t Open the resulting user.js file."
- echo -e "\t-r,\t\t Only download user.js to a temporary file and open it."
- echo -e
- echo 'Deprecated Arguments (they still work for now):'
- echo -e "\t-donotupdate,\t Use instead -d"
- echo -e "\t-update,\t Use instead -u"
- echo -e
- exit 1
- }
- legacy_argument () {
- echo -e "${ORANGE}\nWarning: command line arguments have changed."
- echo -e "$1 has been deprecated and may not work in the future.\n"
- echo -e "Please view the new options using the -h argument.${NC}"
- }
- #########################
- # File Handling #
- #########################
- # Download files
- download_file () {
- declare -r url=$1
- declare -r tf=$(mktemp)
- local dlcmd=''
- if [ $DOWNLOAD_METHOD = 'curl' ]; then
- dlcmd="curl -o $tf"
- else
- dlcmd="wget -O $tf"
- fi
- $dlcmd "${url}" &>/dev/null && echo "$tf" || echo '' # return the temp-filename (or empty string on error)
- }
- open_file () { #expects one argument: file_path
- if [ "$(uname)" == 'Darwin' ]; then
- open "$1"
- elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
- xdg-open "$1"
- else
- echo -e "${RED}Error: Sorry, opening files is not supported for your OS.${NC}"
- fi
- }
- readIniFile () { # expects one argument: absolute path of profiles.ini
- declare -r inifile="$1"
- declare -r tfile=$(mktemp)
- if [ $(grep '^\[Profile' "$inifile" | wc -l) == "1" ]; then ### only 1 profile found
- grep '^\[Profile' -A 4 "$inifile" | grep -v '^\[Profile' > $tfile
- else
- grep -E -v '^\[General\]|^StartWithLastProfile=|^IsRelative=' "$inifile"
- echo ''
- read -p 'Select the profile number ( 0 for Profile0, 1 for Profile1, etc ) : ' -r
- echo -e "\n"
- if [[ $REPLY =~ ^(0|[1-9][0-9]*)$ ]]; then
- grep '^\[Profile'${REPLY} -A 4 "$inifile" | grep -v '^\[Profile'${REPLY} > $tfile
- if [ !$? ]; then
- echo "Profile${REPLY} does not exist!" && exit 1
- fi
- else
- echo "Invalid selection!" && exit 1
- fi
- fi
- declare -r profpath=$(grep '^Path=' $tfile)
- declare -r pathisrel=$(grep '^IsRelative=' $tfile)
- rm "$tfile"
- # update global variable
- if [[ ${pathisrel#*=} == "1" ]]; then
- PROFILE_PATH="$(dirname "$inifile")/${profpath#*=}"
- else
- PROFILE_PATH="${profpath#*=}"
- fi
- }
- getProfilePath () {
- declare -r f1=~/Library/Application\ Support/Firefox/profiles.ini
- declare -r f2=~/.mozilla/firefox/profiles.ini
- if [ "$PROFILE_PATH" = false ]; then
- PROFILE_PATH="$SCRIPT_DIR"
- elif [ "$PROFILE_PATH" = 'list' ]; then
- local ini=''
- if [[ -f "$f1" ]]; then
- ini="$f1"
- elif [[ -f "$f2" ]]; then
- ini="$f2"
- else
- echo -e "${RED}Error: Sorry, -l is not supported for your OS${NC}"
- exit 1
- fi
- readIniFile "$ini" # updates PROFILE_PATH or exits on error
- #else
- # PROFILE_PATH already set by user with -p
- fi
- }
- #########################
- # Update updater.sh #
- #########################
- # Returns the version number of a updater.sh file
- get_updater_version () {
- echo $(sed -n '5 s/.*[[:blank:]]\([[:digit:]]*\.[[:digit:]]*\)/\1/p' "$1")
- }
- # Update updater.sh
- # Default: Check for update, if available, ask user if they want to execute it
- # Args:
- # -donotupdate: New version will not be looked for and update will not occur
- # -update: Check for update, if available, execute without asking
- update_updater () {
- if [ $UPDATE = 'no' ]; then
- return 0 # User signified not to check for updates
- fi
- declare -r tmpfile=$(download_file 'https://raw.githubusercontent.com/ghacksuserjs/ghacks-user.js/master/updater.sh')
- if [[ $(get_updater_version "${SCRIPT_DIR}/updater.sh") < $(get_updater_version "${tmpfile}") ]]; then
- if [ $UPDATE = 'check' ]; then
- echo -e "There is a newer version of updater.sh available. ${RED}Update and execute Y/N?${NC}"
- read -p "" -n 1 -r
- echo -e "\n\n"
- if [[ $REPLY =~ ^[Nn]$ ]]; then
- return 0 # Update available, but user chooses not to update
- fi
- fi
- else
- return 0 # No update available
- fi
- mv "${tmpfile}" "${SCRIPT_DIR}/updater.sh"
- chmod u+x "${SCRIPT_DIR}/updater.sh"
- "${SCRIPT_DIR}/updater.sh" "$@ -d"
- exit 1
- }
- #########################
- # Update user.js #
- #########################
- # Returns version number of a user.js file
- get_userjs_version () {
- echo "$(sed -n '4p' "$1")"
- }
- add_override () {
- input=$1
- if [ -f "$input" ]; then
- echo "" >> user.js
- cat "$input" >> user.js
- echo -e "Status: ${GREEN}Override file appended:${NC} ${input}"
- elif [ -d "$input" ]; then
- FSAVEIFS=$IFS
- IFS=$'\n\b' # Set IFS
- FILES="${input}"/*.js
- for f in $FILES
- do
- add_override "$f"
- done
- IFS=$SAVEIFS # restore $IFS
- else
- echo -e "${ORANGE}Warning: Could not find override file:${NC} ${input}"
- fi
- }
- remove_comments () { # expects 2 arguments: from-file and to-file
- sed -e 's/^[[:space:]]*\/\/.*$//' -e '/^\/\*/,/\*\//d' -e '/^[[:space:]]*$/d' -e 's/);[[:space:]]*\/\/.*/);/' "$1" > "$2"
- }
- # Applies latest version of user.js and any custom overrides
- update_userjs () {
- declare -r newfile=$(download_file 'https://raw.githubusercontent.com/ghacksuserjs/ghacks-user.js/master/user.js')
- echo 'Please observe the following information:'
- echo -e "\tFirefox profile: ${ORANGE}$(pwd)${NC}"
- echo -e "\tAvailable online: ${ORANGE}$(get_userjs_version $newfile)${NC}"
- echo -e "\tCurrently using: ${ORANGE}$(get_userjs_version user.js)\n${NC}\n"
- if [ $CONFIRM = 'yes' ]; then
- echo -e "This script will update to the latest user.js file and append any custom configurations from user-overrides.js. ${RED}Continue Y/N? ${NC}"
- read -p "" -n 1 -r
- echo -e "\n"
- if [[ $REPLY =~ ^[Nn]$ ]]; then
- echo -e "${RED}Process aborted${NC}"
- rm $newfile
- return 1
- fi
- fi
- # Copy a version of user.js to diffs folder for later comparison
- if [ "$COMPARE" = true ]; then
- mkdir -p userjs_diffs
- cp user.js userjs_diffs/past_user.js
- fi
- # backup user.js
- mkdir -p userjs_backups
- local bakname="userjs_backups/user.js.backup.$(date +"%Y-%m-%d_%H%M")"
- if [ $BACKUP = 'single' ]; then
- bakname='userjs_backups/user.js.backup'
- fi
- cp user.js "$bakname"
- mv "${newfile}" user.js
- echo -e "Status: ${GREEN}user.js has been backed up and replaced with the latest version!${NC}"
- # apply overrides
- if [ "$SKIPOVERRIDE" = false ]; then
- while IFS=',' read -ra FILE; do
- add_override "$FILE"
- done <<< "$OVERRIDE"
- fi
- # create diff
- if [ "$COMPARE" = true ]; then
- pastuserjs='userjs_diffs/past_user.js'
- past_nocomments='userjs_diffs/past_userjs.txt'
- current_nocomments='userjs_diffs/current_userjs.txt'
- remove_comments $pastuserjs $past_nocomments
- remove_comments user.js $current_nocomments
- diffname="userjs_diffs/diff_$(date +"%Y-%m-%d_%H%M").txt"
- diff=$(diff -w -B -U 0 $past_nocomments $current_nocomments)
- if [ ! -z "$diff" ]; then
- echo "$diff" > "$diffname"
- echo -e "Status: ${GREEN}A diff file was created:${NC} ${PWD}/${diffname}"
- else
- echo -e "Warning: ${ORANGE}Your new user.js file appears to be identical. No diff file was created.${NC}"
- fi
- rm $past_nocomments $current_nocomments $pastuserjs
- fi
- if [ "$VIEW" = true ]; then open_file "${PWD}/user.js"; fi
- }
- #########################
- # Execute #
- #########################
- if [ $# != 0 ]; then
- readonly legacy_lc=$(echo $1 | tr '[A-Z]' '[a-z]')
- # Display usage if first argument is -help or --help
- if [ $1 = '--help' ] || [ $1 = '-help' ]; then
- usage
- elif [ $legacy_lc = '-donotupdate' ]; then
- UPDATE='no'
- legacy_argument $1
- elif [ $legacy_lc = '-update' ]; then
- UPDATE='yes'
- legacy_argument $1
- else
- while getopts ":hp:ludsno:bcvr" opt; do
- case $opt in
- h)
- usage
- ;;
- p)
- PROFILE_PATH=${OPTARG}
- ;;
- l)
- PROFILE_PATH='list'
- ;;
- u)
- UPDATE='yes'
- ;;
- d)
- UPDATE='no'
- ;;
- s)
- CONFIRM='no'
- ;;
- n)
- SKIPOVERRIDE=true
- ;;
- o)
- OVERRIDE=${OPTARG}
- ;;
- b)
- BACKUP='single'
- ;;
- c)
- COMPARE=true
- ;;
- v)
- VIEW=true
- ;;
- r)
- tfile=$(download_file 'https://raw.githubusercontent.com/ghacksuserjs/ghacks-user.js/master/user.js')
- mv $tfile "${tfile}.js"
- echo -e "${ORANGE}Warning: user.js was saved to temporary file ${tfile}.js${NC}"
- open_file "${tfile}.js"
- exit 1
- ;;
- \?)
- echo -e "${RED}\n Error! Invalid option: -$OPTARG${NC}" >&2
- usage
- ;;
- :)
- echo -e "${RED}Error! Option -$OPTARG requires an argument.${NC}" >&2
- exit 1
- ;;
- esac
- done
- fi
- fi
- show_banner
- update_updater
- getProfilePath # updates PROFILE_PATH or exits on error
- cd "$PROFILE_PATH" && update_userjs
- cd "$CURRDIR"
|