#!/bin/sh
# Copyright (C) 2021 Wojtek Kosior
# Redistribution terms are gathered in the `copyright' file.
. ./shell_utils.sh
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
[ "x$FILE" = "xexports_init.js" ] || echo $FILE # exports_init.js is hardcoded to load first; the entire export system depends on it
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
}
build_main() {
# placate importers of these, as they are exported by the yet-to-be-created exports_init.js
EXPORTS__browser=exports_init.js
EXPORTS__is_chrome=exports_init.js
EXPORTS__is_mozilla=exports_init.js
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)"
for DIR in $(find $SCRIPTDIRS -type d); do
mkdir -p $BUILDDIR/$DIR
done
CHROMIUM_KEY=''
CHROMIUM_UPDATE_URL=''
GECKO_APPLICATIONS=''
if [ "x$UPDATE_URL" != x ]; then
UPDATE_URL=",\n \"update_url\": \"$UPDATE_URL\""
fi
if [ "$BROWSER" = "chromium" ]; then
CHROMIUM_KEY="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)"
CHROMIUM_KEY=$(echo chromium-key-dummy-file-$CHROMIUM_KEY | tr / -)
touch "$BUILDDIR"/$CHROMIUM_KEY
CHROMIUM_UPDATE_URL="$UPDATE_URL"
CHROMIUM_KEY="\n\
// WARNING!!!\n\
// EACH USER SHOULD REPLACE DUMMY FILE's VALUE WITH A UNIQUE ONE!!!\n\
// OTHERWISE, SECURITY CAN BE TRIVIALLY COMPROMISED!\n\
// Only relevant to users of chrome-based browsers.\n\
// Users of Firefox forks are safe.\n\
\"$CHROMIUM_KEY\"\
"
else
GECKO_APPLICATIONS="\n\
\"applications\": {\n\
\"gecko\": {\n\
\"id\": \"{6fe13369-88e9-440f-b837-5012fb3bedec}\",\n\
\"strict_min_version\": \"60.0\"$UPDATE_URL\n\
}\n\
},"
fi
sed "\
s^_GECKO_APPLICATIONS_^$GECKO_APPLICATIONS^
s^_CHROMIUM_KEY_^$CHROMIUM_KEY^
s^_CHROMIUM_UPDATE_URL_^$CHROMIUM_UPDATE_URL^
s^_BGSCRIPTS_^$BGSCRIPTS^
s^_CONTENTSCRIPTS_^$CONTENTSCRIPTS^" \
< manifest.json > $BUILDDIR/manifest.json
./process_html_file.sh html/display-panel.html |
sed "s^_POPUPSCRIPTS_^$POPUPSCRIPTS^" \
> $BUILDDIR/html/display-panel.html
./process_html_file.sh html/options.html |
sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \
> $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\";
({fun: (function() {
$(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)
})}).fun();") > $BUILDDIR/$FILE
fi
done
if [ "$BROWSER" = "chromium" ]; then
cat > $BUILDDIR/exports_init.js < $BUILDDIR/exports_init.js < "$MOZILLA_FILE"
done
fi
if [ "$BROWSER" = "mozilla" ]; then
for CHROMIUM_FILE in $(find $BUILDDIR -name "CHROMIUM_*"); do
echo > "$CHROMIUM_FILE"
done
fi
}
main() {
if [ "x$1" = "xmozilla" -o "x$1" = "xchromium" ]; then
BROWSER=$1
else
errcho "usage: $0 mozilla|chromium [source directory] [update url]"
exit 1
fi
SRCDIR="${2:-.}"
if [ -d "$SRCDIR" ]; then
BUILDDIR="$(realpath build_$BROWSER)"
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
cd "$SRCDIR"
else
errcho "usage: $0 mozilla|chromium [source directory] [update url]"
exit 2
fi
UPDATE_URL="$3"
build_main
}
main "$@"