#!/bin/sh # Copyright (C) 2021 Wojtek Kosior # Redistribution terms are gathered in the `copyright' file. ENDL=" " errcho() { echo "$@" >&2 } map_set_instr() { echo "$1__$2='$3'" } map_set() { eval "$(map_set_instr "$@")" } map_get() { eval "echo \"\$$1__$2\"" } map_del_instr() { echo "unset $1__$2" } map_del() { eval "$(map_del_instr "$@")" } sanitize() { echo "$1" | tr /.- _ } handle_export_line() { if [ "x$1" = "xEXPORTS_START" ]; then if [ "$STATE" = "before_block" ]; then STATE="in_block" fi elif [ "x$1" = "xEXPORT" ]; then if [ "$STATE" != "in_block" ]; then return fi EXPORTCODE="${EXPORTCODE}window.killtheweb.$2 = $2;$ENDL" PREVIOUS_FILE="$(map_get EXPORTS $2)" if [ "x$PREVIOUS_FILE" != "x" ]; then errcho "export $2 present in both $PREVIOUS_FILE and $FILE" return 1 fi map_set_instr EXPORTS $2 "$FILE" elif [ "x$1" = "xEXPORTS_END" ]; then if [ "$STATE" = "in_block" ]; then STATE="after_block" fi fi } translate_exports() { STATE="before_block" EXPORTCODE='' while read EXPORT_LINE; do handle_export_line $EXPORT_LINE || return 1 done map_set_instr EXPORTCODES $FILEKEY "$EXPORTCODE" } add_exports() { FILE="$1" FILEKEY="$(sanitize "$FILE")" eval "$(grep -o 'EXPORT.\+' "$1" | translate_exports || exit 1)" } handle_import_line() { if [ "x$1" = "xIMPORTS_START" ]; then if [ "$STATE" = "before_block" ]; then STATE="in_block" fi elif [ "x$1" = "xIMPORT" ]; then if [ "$STATE" != "in_block" ]; then return fi IMPORTCODE="${IMPORTCODE}const $2 = window.killtheweb.$2;$ENDL" IMPORTS="$IMPORTS $2" elif [ "x$1" = "xIMPORTS_END" ]; then if [ "$STATE" = "in_block" ]; then STATE="after_block" fi fi } translate_imports() { STATE="before_block" IMPORTCODE='' IMPORTS='' while read IMPORT_LINE; do handle_import_line $IMPORT_LINE || return 1 done map_set_instr IMPORTCODES $FILEKEY "$IMPORTCODE" map_set_instr IMPORTS $FILEKEY "$IMPORTS" } add_imports() { FILE="$1" FILEKEY="$(sanitize "$FILE")" eval "$(grep -o 'IMPORT.\+' "$1" | translate_imports || exit 1)" } compute_scripts_list_rec() { local FILE="$1" local FILEKEY=$(sanitize "$1") local FILESTATE="$(map_get FILESTATES $FILEKEY)" if [ "xprocessed" = "x$FILESTATE" ]; then return fi if [ "xprocessing" = "x$FILESTATE" ]; then errcho "import loop on $FILE" return 1 fi USED="$USED $FILEKEY" map_set FILESTATES $FILEKEY "processing" local IMPORT for IMPORT in $(map_get IMPORTS $FILEKEY); do NEXT_FILE="$(map_get EXPORTS $IMPORT)" if [ "x" = "x$NEXT_FILE" ]; then errcho "nothing exports $IMPORT, required by $FILE" return 1 fi if ! compute_scripts_list_rec "$NEXT_FILE"; then errcho "when satisfying $IMPORT for $FILE" return 1 fi done echo $FILE map_set FILESTATES $FILEKEY "processed" } compute_scripts_list() { USED='' echo COMPUTED_SCRIPTS=\"exports_init.js compute_scripts_list_rec "$1" echo \" for FILEKEY in $USED; do map_set_instr USED $FILEKEY yes done } as_json_list() { while true; do if [ "x" = "x$2" ]; then echo -n '\\n'"\t\t\"$1\""'\\n\t' return fi echo -n '\\n'"\t\t\"$1\"," shift done } as_html_list() { while [ "x" != "x$1" ]; do echo -n '\\n'" " shift done } set_browser() { if [ "x$1" = "xmozilla" -o "x$1" = "xchromium" ]; then BROWSER="$1" else errcho "usage: $0 mozilla|chromium" exit 1 fi } main() { set_browser "$1" SCRIPTDIRS='background html common content' SCRIPTS=$(find $SCRIPTDIRS -name '[^.#]*.js') for SCRIPT in $SCRIPTS; do add_exports $SCRIPT add_imports $SCRIPT done eval "$(compute_scripts_list background/main.js || exit 1)" BGSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)" eval "$(compute_scripts_list content/main.js || exit 1)" CONTENTSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)" eval "$(compute_scripts_list html/display-panel.js || exit 1)" POPUPSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)" eval "$(compute_scripts_list html/options_main.js || exit 1)" OPTIONSSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)" BUILDDIR=build_$BROWSER rm -rf $BUILDDIR mkdir $BUILDDIR for DIR in $(find $SCRIPTDIRS -type d); do mkdir -p $BUILDDIR/$DIR done CHROMIUM_KEY='' GECKO_APPLICATIONS='' if [ "$BROWSER" = "chromium" ]; then CHROMIUM_KEY="\n\ \n\ // WARNING!!!\n\ // EACH USER SHOULD REPLACE \"key\" WITH A UNIQUE VALUE!!!\n\ // OTHERWISE, SECURITY CAN BE TRIVIALLY COMPROMISED!\n\ //\n\ // A unique key can be generated with:\n\ // $ ssh-keygen -f /path/to/new/key.pem -t rsa -b 1024\n\ //\n\ // Only relevant to users of chrome-based browsers.\n\ // Users of Firefox forks are safe.\n\ \n\ \"key\": \"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcnNhAAAAAwEAAQAAAIEA+0GT5WNmRRo8e5tL9+BmNtY6aBPwLIgbPnLShYBMSR40iYwLTsccrkwBXb3bs1o4p6q5WJugI8Lsia+GXZc/XHGFkq7D1aWiTxlJLs8z0JC2TQ2/yatYmBMchogYGeeUfP7aI7JJZwpATts+VhIvgga/4FYj+DijMIEpwdckqFEAAAII4Dh7HOA4exwAAAAHc3NoLXJzYQAAAIEA+0GT5WNmRRo8e5tL9+BmNtY6aBPwLIgbPnLShYBMSR40iYwLTsccrkwBXb3bs1o4p6q5WJugI8Lsia+GXZc/XHGFkq7D1aWiTxlJLs8z0JC2TQ2/yatYmBMchogYGeeUfP7aI7JJZwpATts+VhIvgga/4FYj+DijMIEpwdckqFEAAAADAQABAAAAgEHB5/MhEKMFOs8e1cMJ97ZiWubiUPlWpcqyQmauLUj1nspg3JTBh8AWJEVkaxuFgU5gYCHQmRjC6yUdywyziOEkFA4r/WpX4WmbIe+GQHRHhitLN0dgF8N6/fVNOoa5StTdfZqyl23pVXyepoDNjrJFKyupqPMmpwfH5lGr9RwBAAAAQG76HflB/5j8P2YgIYX6dQT4Ei0SqiIjNVy7jFJUQDKSJg/PYkedE02JZJBJPcMYxEJUxXtMgq+upamNILfkmY0AAABBAP4v0O5dqjy16xDDFzb4DPNAcw5Za9KJaXKVkUuKXMNZOKTR0RC/upjNTmttY980RKdIx5zA25dO8cx563bSDIsAAABBAP0MaOpBiai/eRmLqhlthHODa+Mur6W3uc9PyhWhgDBjLNMR/doaYeyfVKxtIiN3a+HkN++G+vbokRweQv++bhMAAAANdXJ6QGxvY2FsaG9zdAECAwQFBg==\"," else GECKO_APPLICATIONS="\n\ \"applications\": {\n\ \"gecko\": {\n\ \"id\": \"{6fe13369-88e9-440f-b837-5012fb3bedec}\",\n\ \"strict_min_version\": \"60.0\"\n\ }\n\ }," fi sed "\ s^_GECKO_APPLICATIONS_^$GECKO_APPLICATIONS^ s^_CHROMIUM_KEY_^$CHROMIUM_KEY^ s^_BGSCRIPTS_^$BGSCRIPTS^ s^_CONTENTSCRIPTS_^$CONTENTSCRIPTS^" \ < manifest.json > $BUILDDIR/manifest.json sed "s^_POPUPSCRIPTS_^$POPUPSCRIPTS^" \ < html/display-panel.html > $BUILDDIR/html/display-panel.html sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \ < html/options.html > $BUILDDIR/html/options.html for FILE in $SCRIPTS; do FILEKEY=$(sanitize "$FILE") if [ "xyes" != "x$(map_get USED $FILEKEY)" ]; then errcho "WARNING! $FILE not used" else (echo "\ \"use strict\"; (() => { $(map_get IMPORTCODES $FILEKEY) "; # A hack to insert the contents of default_settings.json at the appropriate location in background/main.js if [ "$FILE" = "background/main.js" ]; then # Uses an internal sed expression to escape and indent the JSON file for use in the external sed expression sed 's/^ `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/ /; s/$/\\/' < default_settings.json) "/g < "$FILE" else cat $FILE fi echo " $(map_get EXPORTCODES $FILEKEY) })();") > $BUILDDIR/$FILE fi done echo "\ window.killtheweb={}; window.browser = this.browser; /* fix for stupid Firefox */ " > $BUILDDIR/exports_init.js cp -r icons/ copyright licenses/ $BUILDDIR } main "$@"