#!/bin/sh
#
# The React bundle is static: nginx never passes its own environment to it, and
# every process.env value was frozen into the JavaScript at build time. This
# script runs at container start, dumps the environment Kubernetes gave the pod
# next to the app code, and then hands over to nginx.
#
#   $APP_DIR/.env    KEY="VALUE" lines, for debugging and anything reading dotenv
#   $APP_DIR/env.js  window.__ENV__["KEY"] = "VALUE"; loaded by index.html
#
# $APP_DIR is the nginx web root, so both files are publicly downloadable.
# Only variables matching RUNTIME_ENV_PREFIX are written, which keeps the
# secrets mounted through envFrom out of them. RUNTIME_ENV_PREFIX takes a
# space separated list of prefixes; set it to "" to export the whole
# environment (and accept that anyone can read it).
#

set -eu

APP_DIR="${APP_DIR:-/app}"
RUNTIME_ENV_PREFIX="${RUNTIME_ENV_PREFIX-REACT_APP_}"

ENV_FILE="$APP_DIR/.env"
ENV_JS_FILE="$APP_DIR/env.js"

# Escapes a value so it is safe inside a double quoted dotenv value and inside a
# double quoted JavaScript string: backslash, double quote and newline.
escape()
{
	printf '%s' "$1" \
		| tr -d '\r' \
		| sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' \
		| awk 'NR > 1 { printf "\\n" } { printf "%s", $0 }'
}

matches_prefix()
{
	# No prefix configured means export everything.
	if [ -z "$RUNTIME_ENV_PREFIX" ]; then
		return 0
	fi
	for prefix in $RUNTIME_ENV_PREFIX; do
		case "$1" in
			"$prefix"*) return 0 ;;
		esac
	done
	return 1
}

mkdir -p "$APP_DIR"

: > "$ENV_FILE.tmp"
{
	echo "// Generated at container start by entrypoint.sh - do not edit."
	echo "window.__ENV__ = window.__ENV__ || {};"
} > "$ENV_JS_FILE.tmp"

# ENVIRON is POSIX awk, so this works on both mawk and gawk. Names cannot
# contain newlines, values can, which is why only the names are listed here and
# each value is read back with printenv.
names=$(awk 'BEGIN { for (name in ENVIRON) if (name ~ /^[A-Za-z_][A-Za-z0-9_]*$/) print name }' | sort)

count=0
exported=""
for name in $names; do
	if ! matches_prefix "$name"; then
		continue
	fi
	value=$(escape "$(printenv "$name" || true)")
	printf '%s="%s"\n' "$name" "$value" >> "$ENV_FILE.tmp"
	printf 'window.__ENV__["%s"] = "%s";\n' "$name" "$value" >> "$ENV_JS_FILE.tmp"
	count=$((count + 1))
	exported="$exported $name"
done

mv "$ENV_FILE.tmp" "$ENV_FILE"
mv "$ENV_JS_FILE.tmp" "$ENV_JS_FILE"

echo "[entrypoint] exported $count variable(s) to $ENV_FILE and $ENV_JS_FILE:$exported"

# nginx serves *.js with a one year immutable cache, so point index.html at a new
# env.js?v= on every change, otherwise browsers keep the environment of the
# deployment they first loaded.
if [ -f "$APP_DIR/index.html" ]; then
	version=$(md5sum "$ENV_JS_FILE" | cut -c1-8)
	sed -i "s|env\\.js?v=[^\"]*|env.js?v=$version|" "$APP_DIR/index.html"
fi

# Anything passed to the container wins, otherwise start nginx (the image CMD).
if [ "$#" -gt 0 ]; then
	exec "$@"
fi

exec nginx -g "daemon off;"
