updater.sh 13 KB

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