#!/bin/sh
# shellcheck disable=SC1017
# Copyright 2020-2021 Haelwenn (lanodan) Monnier <contact+gemini@hacktivis.me>
# Distributed under the terms of the GNU Affero General Public License version 3

# AGPL-3 because it's a service on the internet, screw permissive licences for these

# Notes:
# - URLs are barely parsed and mostly taken as-is, which could be dangerous
# - Recognised hostnames are directories in $GEMDIR, they must also have a $host:1965 symlink
# - stunnel chroot ability is untested for now
# - Lastest known version of the specification: v0.14.3, November 29th 2020

export GEMDIR="/srv/gemini"

bubblewrap() {
	bwrap \
		--unshare-user --uid 65534 --gid 65534 \
		--unshare-ipc --unshare-pid --unshare-uts --unshare-cgroup-try \
		--ro-bind /bin /bin \
		--ro-bind /lib /lib \
		--ro-bind /lib64 /lib64 \
		--ro-bind /usr /usr \
		--ro-bind /git /git \
		--ro-bind /etc /etc \
		--ro-bind "${GEMDIR}" "${GEMDIR}" \
		--chdir "${GEMDIR}" \
		--proc /proc \
		--dev /dev \
		--die-with-parent \
		"$@"
}

IFS=#'
' read -r line
# ' hack for vis editor to reset hightlighting…

query="${line#gemini://}"
query="${query%%../*}"
query="${query//%20/ }"
path="$GEMDIR/${query//\?*}"
status="--"

if echo "$path" | grep -Eq '.gmi$'
then
	mime="text/gemini; charset=utf-8"
else
	mime=$(file --mime -b "$path" 2>/dev/null)
fi

if [ -r "$path" -a -f "$path" ]
then
	if echo "$query" | grep -Eq '/cgi-bin/'
	then
		if [ -x "$path" -a -f "$path" ]
		then
			if echo "$query" | grep -Eq '\?'
			then
				bubblewrap "./${query//\?*}" "${query//*\?}"
			else
				bubblewrap "./${query//\?*}" ""
			fi
			status="x$?"
		else
			status="50"
			printf '50 File not executable or non-existent\r\n'
		fi
	else
		status="20"
		printf '20 %s\r\n' "$mime"
		cat "$path" 2>/dev/null
	fi
elif [ -r "$path" -a -d "$path" ]
then
	if echo "$path" | grep -Eq '/$'
	then
		if [ -r "$path/index.gmi" -a -f "$path/index.gmi" ]
		then
			status="20"
			printf '20 text/gemini; charset=utf-8\r\n'
			cat "$path/index.gmi" 2>/dev/null
		else
			status="20"
			printf '20 text/gemini; charset=utf-8\r\n'
			printf '# Index of %s\n' "$query"
			cd "$path" && find . -mindepth 1 -maxdepth 1 | sed -e 's; ;%20;g' -e "s;^\./;=> ;" 2>/dev/null
		fi
	else
		status="30"
		printf '30 gemini://%s/\r\n' "$query"
	fi
else
	status="50"
	printf '50 File not readable or non-existent\r\n'
fi

# I know… blame France data rentention policy
logger -p local0.notice "${REMOTE_HOST:-?host?}	${REMOTE_PORT:-?port?}	${line} ${status}" 2>/dev/null 1>/dev/null