updater.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #!/usr/bin/env bash
  2. ## ghacks-user.js updater for macOS and Linux
  3. ## version: 2.5
  4. ## Author: Pat Johnson (@overdodactyl)
  5. ## Additional contributors: @earthlng, @ema-pe, @claustromaniac
  6. ## DON'T GO HIGHER THAN VERSION x.9 !! ( because of ASCII comparison in update_updater() )
  7. readonly CURRDIR=$(pwd)
  8. sfp=$(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null || greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null)
  9. if [ -z "$sfp" ]; then sfp=${BASH_SOURCE[0]}; fi
  10. readonly SCRIPT_DIR=$(dirname "${sfp}")
  11. #########################
  12. # Base variables #
  13. #########################
  14. # Colors used for printing
  15. RED='\033[0;31m'
  16. BLUE='\033[0;34m'
  17. BBLUE='\033[1;34m'
  18. GREEN='\033[0;32m'
  19. ORANGE='\033[0;33m'
  20. CYAN='\033[0;36m'
  21. NC='\033[0m' # No Color
  22. # Argument defaults
  23. UPDATE='check'
  24. CONFIRM='yes'
  25. OVERRIDE='user-overrides.js'
  26. BACKUP='multiple'
  27. COMPARE=false
  28. SKIPOVERRIDE=false
  29. VIEW=false
  30. PROFILE_PATH=false
  31. ESR=false
  32. # Download method priority: curl -> wget
  33. DOWNLOAD_METHOD=''
  34. if [[ $(command -v 'curl') ]]; then
  35. DOWNLOAD_METHOD='curl'
  36. elif [[ $(command -v 'wget') ]]; then
  37. DOWNLOAD_METHOD='wget'
  38. else
  39. echo -e "${RED}This script requires curl or wget.\nProcess aborted${NC}"
  40. exit 0
  41. fi
  42. show_banner () {
  43. echo -e "${BBLUE}\n"
  44. echo ' ############################################################################'
  45. echo ' #### ####'
  46. echo ' #### ghacks user.js ####'
  47. echo ' #### Hardening the Privacy and Security Settings of Firefox ####'
  48. echo ' #### Maintained by @Thorin-Oakenpants and @earthlng ####'
  49. echo ' #### Updater for macOS and Linux by @overdodactyl ####'
  50. echo ' #### ####'
  51. echo ' ############################################################################'
  52. echo -e "${NC}\n"
  53. echo -e "Documentation for this script is available here: ${CYAN}https://github.com/ghacksuserjs/ghacks-user.js/wiki/3.3-Updater-Scripts${NC}\n"
  54. }
  55. #########################
  56. # Arguments #
  57. #########################
  58. usage() {
  59. echo -e "${BLUE}\nUsage: $0 [-h] [-p PROFILE] [-u] [-d] [-s] [-n] [-b] [-c] [-v] [-r] [-e] [-o OVERRIDE]\n${NC}" 1>&2 # Echo usage string to standard error
  60. echo 'Optional Arguments:'
  61. echo -e "\t-h,\t\t Show this help message and exit."
  62. echo -e "\t-p PROFILE,\t Path to your Firefox profile (if different than the dir of this script)"
  63. echo -e "\t\t\t IMPORTANT: if the path include spaces, wrap the entire argument in quotes."
  64. echo -e "\t-l, \t\t Choose your Firefox profile from a list"
  65. echo -e "\t-u,\t\t Update updater.sh and execute silently. Do not seek confirmation."
  66. echo -e "\t-d,\t\t Do not look for updates to updater.sh."
  67. echo -e "\t-s,\t\t Silently update user.js. Do not seek confirmation."
  68. echo -e "\t-b,\t\t Only keep one backup of each file."
  69. echo -e "\t-c,\t\t Create a diff file comparing old and new user.js within userjs_diffs. "
  70. echo -e "\t-o OVERRIDE,\t Filename or path to overrides file (if different than user-overrides.js)."
  71. echo -e "\t\t\t If used with -p, paths should be relative to PROFILE or absolute paths"
  72. echo -e "\t\t\t If given a directory, all files inside will be appended recursively."
  73. echo -e "\t\t\t You can pass multiple files or directories by passing a comma separated list."
  74. echo -e "\t\t\t\t Note: If a directory is given, only files inside ending in the extension .js are appended"
  75. echo -e "\t\t\t\t IMPORTANT: do not add spaces between files/paths. Ex: -o file1.js,file2.js,dir1"
  76. echo -e "\t\t\t\t IMPORTANT: if any files/paths include spaces, wrap the entire argument in quotes."
  77. echo -e "\t\t\t\t\t Ex: -o \"override folder\" "
  78. echo -e "\t-n,\t\t Do not append any overrides, even if user-overrides.js exists."
  79. echo -e "\t-v,\t\t Open the resulting user.js file."
  80. echo -e "\t-r,\t\t Only download user.js to a temporary file and open it."
  81. echo -e "\t-e,\t\t Activate ESR related preferences."
  82. echo -e
  83. echo 'Deprecated Arguments (they still work for now):'
  84. echo -e "\t-donotupdate,\t Use instead -d"
  85. echo -e "\t-update,\t Use instead -u"
  86. echo -e
  87. exit 1
  88. }
  89. legacy_argument () {
  90. echo -e "${ORANGE}\nWarning: command line arguments have changed."
  91. echo -e "$1 has been deprecated and may not work in the future.\n"
  92. echo -e "Please view the new options using the -h argument.${NC}"
  93. }
  94. #########################
  95. # File Handling #
  96. #########################
  97. # Download files
  98. download_file () {
  99. declare -r url=$1
  100. declare -r tf=$(mktemp)
  101. local dlcmd=''
  102. if [ $DOWNLOAD_METHOD = 'curl' ]; then
  103. dlcmd="curl -o $tf"
  104. else
  105. dlcmd="wget -O $tf"
  106. fi
  107. $dlcmd "${url}" &>/dev/null && echo "$tf" || echo '' # return the temp-filename (or empty string on error)
  108. }
  109. open_file () { #expects one argument: file_path
  110. if [ "$(uname)" == 'Darwin' ]; then
  111. open "$1"
  112. elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
  113. xdg-open "$1"
  114. else
  115. echo -e "${RED}Error: Sorry, opening files is not supported for your OS.${NC}"
  116. fi
  117. }
  118. readIniFile () { # expects one argument: absolute path of profiles.ini
  119. declare -r inifile="$1"
  120. declare -r tfile=$(mktemp)
  121. if [ $(grep '^\[Profile' "$inifile" | wc -l) == "1" ]; then ### only 1 profile found
  122. grep '^\[Profile' -A 4 "$inifile" | grep -v '^\[Profile' > $tfile
  123. else
  124. grep -E -v '^\[General\]|^StartWithLastProfile=|^IsRelative=' "$inifile"
  125. echo ''
  126. read -p 'Select the profile number ( 0 for Profile0, 1 for Profile1, etc ) : ' -r
  127. echo -e "\n"
  128. if [[ $REPLY =~ ^(0|[1-9][0-9]*)$ ]]; then
  129. grep '^\[Profile'${REPLY} -A 4 "$inifile" | grep -v '^\[Profile'${REPLY} > $tfile
  130. if [[ "$?" != "0" ]]; then
  131. echo "Profile${REPLY} does not exist!" && exit 1
  132. fi
  133. else
  134. echo "Invalid selection!" && exit 1
  135. fi
  136. fi
  137. declare -r profpath=$(grep '^Path=' $tfile)
  138. declare -r pathisrel=$(grep '^IsRelative=' $tfile)
  139. rm "$tfile"
  140. # update global variable
  141. if [[ ${pathisrel#*=} == "1" ]]; then
  142. PROFILE_PATH="$(dirname "$inifile")/${profpath#*=}"
  143. else
  144. PROFILE_PATH="${profpath#*=}"
  145. fi
  146. }
  147. getProfilePath () {
  148. declare -r f1=~/Library/Application\ Support/Firefox/profiles.ini
  149. declare -r f2=~/.mozilla/firefox/profiles.ini
  150. if [ "$PROFILE_PATH" = false ]; then
  151. PROFILE_PATH="$SCRIPT_DIR"
  152. elif [ "$PROFILE_PATH" = 'list' ]; then
  153. local ini=''
  154. if [[ -f "$f1" ]]; then
  155. ini="$f1"
  156. elif [[ -f "$f2" ]]; then
  157. ini="$f2"
  158. else
  159. echo -e "${RED}Error: Sorry, -l is not supported for your OS${NC}"
  160. exit 1
  161. fi
  162. readIniFile "$ini" # updates PROFILE_PATH or exits on error
  163. #else
  164. # PROFILE_PATH already set by user with -p
  165. fi
  166. }
  167. #########################
  168. # Update updater.sh #
  169. #########################
  170. # Returns the version number of a updater.sh file
  171. get_updater_version () {
  172. echo $(sed -n '5 s/.*[[:blank:]]\([[:digit:]]*\.[[:digit:]]*\)/\1/p' "$1")
  173. }
  174. # Update updater.sh
  175. # Default: Check for update, if available, ask user if they want to execute it
  176. # Args:
  177. # -donotupdate: New version will not be looked for and update will not occur
  178. # -update: Check for update, if available, execute without asking
  179. update_updater () {
  180. if [ $UPDATE = 'no' ]; then
  181. return 0 # User signified not to check for updates
  182. fi
  183. declare -r tmpfile=$(download_file 'https://raw.githubusercontent.com/ghacksuserjs/ghacks-user.js/master/updater.sh')
  184. if [[ $(get_updater_version "${SCRIPT_DIR}/updater.sh") < $(get_updater_version "${tmpfile}") ]]; then
  185. if [ $UPDATE = 'check' ]; then
  186. echo -e "There is a newer version of updater.sh available. ${RED}Update and execute Y/N?${NC}"
  187. read -p "" -n 1 -r
  188. echo -e "\n\n"
  189. if [[ $REPLY =~ ^[Nn]$ ]]; then
  190. return 0 # Update available, but user chooses not to update
  191. fi
  192. fi
  193. else
  194. return 0 # No update available
  195. fi
  196. mv "${tmpfile}" "${SCRIPT_DIR}/updater.sh"
  197. chmod u+x "${SCRIPT_DIR}/updater.sh"
  198. "${SCRIPT_DIR}/updater.sh" "$@" -d
  199. exit 1
  200. }
  201. #########################
  202. # Update user.js #
  203. #########################
  204. # Returns version number of a user.js file
  205. get_userjs_version () {
  206. if [ -e $1 ]; then
  207. echo "$(sed -n '4p' "$1")"
  208. else
  209. echo "Not detected."
  210. fi
  211. }
  212. add_override () {
  213. input=$1
  214. if [ -f "$input" ]; then
  215. echo "" >> user.js
  216. cat "$input" >> user.js
  217. echo -e "Status: ${GREEN}Override file appended:${NC} ${input}"
  218. elif [ -d "$input" ]; then
  219. FSAVEIFS=$IFS
  220. IFS=$'\n\b' # Set IFS
  221. FILES="${input}"/*.js
  222. for f in $FILES
  223. do
  224. add_override "$f"
  225. done
  226. IFS=$SAVEIFS # restore $IFS
  227. else
  228. echo -e "${ORANGE}Warning: Could not find override file:${NC} ${input}"
  229. fi
  230. }
  231. remove_comments () { # expects 2 arguments: from-file and to-file
  232. sed -e 's/^[[:space:]]*\/\/.*$//' -e '/^\/\*/,/\*\//d' -e '/^[[:space:]]*$/d' -e 's/);[[:space:]]*\/\/.*/);/' "$1" > "$2"
  233. }
  234. # Applies latest version of user.js and any custom overrides
  235. update_userjs () {
  236. declare -r newfile=$(download_file 'https://raw.githubusercontent.com/ghacksuserjs/ghacks-user.js/master/user.js')
  237. echo 'Please observe the following information:'
  238. echo -e "\tFirefox profile: ${ORANGE}$(pwd)${NC}"
  239. echo -e "\tAvailable online: ${ORANGE}$(get_userjs_version $newfile)${NC}"
  240. echo -e "\tCurrently using: ${ORANGE}$(get_userjs_version user.js)\n${NC}\n"
  241. if [ $CONFIRM = 'yes' ]; then
  242. 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}"
  243. read -p "" -n 1 -r
  244. echo -e "\n"
  245. if [[ $REPLY =~ ^[Nn]$ ]]; then
  246. echo -e "${RED}Process aborted${NC}"
  247. rm $newfile
  248. return 1
  249. fi
  250. fi
  251. # Copy a version of user.js to diffs folder for later comparison
  252. if [ "$COMPARE" = true ]; then
  253. mkdir -p userjs_diffs
  254. cp user.js userjs_diffs/past_user.js &>/dev/null
  255. fi
  256. # backup user.js
  257. mkdir -p userjs_backups
  258. local bakname="userjs_backups/user.js.backup.$(date +"%Y-%m-%d_%H%M")"
  259. if [ $BACKUP = 'single' ]; then
  260. bakname='userjs_backups/user.js.backup'
  261. fi
  262. cp user.js "$bakname" &>/dev/null
  263. mv "${newfile}" user.js
  264. echo -e "Status: ${GREEN}user.js has been backed up and replaced with the latest version!${NC}"
  265. if [ "$ESR" = true ]; then
  266. sed -e 's/\/\* \(ESR[0-9]\{2,\}\.x still uses all.*\)/\/\/ \1/' user.js > user.js.tmp && mv user.js.tmp user.js
  267. echo -e "Status: ${GREEN}ESR related preferences have been activated!${NC}"
  268. fi
  269. # apply overrides
  270. if [ "$SKIPOVERRIDE" = false ]; then
  271. while IFS=',' read -ra FILE; do
  272. add_override "$FILE"
  273. done <<< "$OVERRIDE"
  274. fi
  275. # create diff
  276. if [ "$COMPARE" = true ]; then
  277. pastuserjs='userjs_diffs/past_user.js'
  278. past_nocomments='userjs_diffs/past_userjs.txt'
  279. current_nocomments='userjs_diffs/current_userjs.txt'
  280. remove_comments $pastuserjs $past_nocomments
  281. remove_comments user.js $current_nocomments
  282. diffname="userjs_diffs/diff_$(date +"%Y-%m-%d_%H%M").txt"
  283. diff=$(diff -w -B -U 0 $past_nocomments $current_nocomments)
  284. if [ ! -z "$diff" ]; then
  285. echo "$diff" > "$diffname"
  286. echo -e "Status: ${GREEN}A diff file was created:${NC} ${PWD}/${diffname}"
  287. else
  288. echo -e "Warning: ${ORANGE}Your new user.js file appears to be identical. No diff file was created.${NC}"
  289. if [ $BACKUP = 'multiple' ]; then
  290. rm $bakname &>/dev/null
  291. fi
  292. fi
  293. rm $past_nocomments $current_nocomments $pastuserjs &>/dev/null
  294. fi
  295. if [ "$VIEW" = true ]; then open_file "${PWD}/user.js"; fi
  296. }
  297. #########################
  298. # Execute #
  299. #########################
  300. if [ $# != 0 ]; then
  301. readonly legacy_lc=$(echo $1 | tr '[A-Z]' '[a-z]')
  302. # Display usage if first argument is -help or --help
  303. if [ $1 = '--help' ] || [ $1 = '-help' ]; then
  304. usage
  305. elif [ $legacy_lc = '-donotupdate' ]; then
  306. UPDATE='no'
  307. legacy_argument $1
  308. elif [ $legacy_lc = '-update' ]; then
  309. UPDATE='yes'
  310. legacy_argument $1
  311. else
  312. while getopts ":hp:ludsno:bcvre" opt; do
  313. case $opt in
  314. h)
  315. usage
  316. ;;
  317. p)
  318. PROFILE_PATH=${OPTARG}
  319. ;;
  320. l)
  321. PROFILE_PATH='list'
  322. ;;
  323. u)
  324. UPDATE='yes'
  325. ;;
  326. d)
  327. UPDATE='no'
  328. ;;
  329. s)
  330. CONFIRM='no'
  331. ;;
  332. n)
  333. SKIPOVERRIDE=true
  334. ;;
  335. o)
  336. OVERRIDE=${OPTARG}
  337. ;;
  338. b)
  339. BACKUP='single'
  340. ;;
  341. c)
  342. COMPARE=true
  343. ;;
  344. v)
  345. VIEW=true
  346. ;;
  347. e)
  348. ESR=true
  349. ;;
  350. r)
  351. tfile=$(download_file 'https://raw.githubusercontent.com/ghacksuserjs/ghacks-user.js/master/user.js')
  352. mv $tfile "${tfile}.js"
  353. echo -e "${ORANGE}Warning: user.js was saved to temporary file ${tfile}.js${NC}"
  354. open_file "${tfile}.js"
  355. exit 1
  356. ;;
  357. \?)
  358. echo -e "${RED}\n Error! Invalid option: -$OPTARG${NC}" >&2
  359. usage
  360. ;;
  361. :)
  362. echo -e "${RED}Error! Option -$OPTARG requires an argument.${NC}" >&2
  363. exit 1
  364. ;;
  365. esac
  366. done
  367. fi
  368. fi
  369. show_banner
  370. update_updater $@
  371. getProfilePath # updates PROFILE_PATH or exits on error
  372. cd "$PROFILE_PATH" && update_userjs
  373. cd "$CURRDIR"