#!/bin/sh
#
# Copyright (c) 2025 Stefan Sperling <stsp@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

. ../cmdline/common.sh
. ./common.sh

test_login() {
	local testroot=`test_init login 1`

	GOTSYS_ECDSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub | \
		cut -d' ' -f2)
	GOTSYS_ED25519_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub | \
		cut -d' ' -f2)
	GOTSYS_RSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub | \
		cut -d' ' -f2)

	got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got checkout failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
	crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
	sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
	cat > ${testroot}/wt/gotsys.conf <<EOF
user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
}
repository gotsys.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository testrepo.git {
	permit rw ${GOTSYSD_TEST_USER}
}
repository gottestdev.git {
	permit rw ${GOTSYSD_DEV_USER}
}
repository hidden.git {
	permit rw ${GOTSYSD_TEST_USER}
}
web server "${VMIP}" {
	repository testrepo {
		permit ${GOTSYSD_TEST_USER}
	}
	repository gottestdev {
		permit ${GOTSYSD_DEV_USER}
		deny ${GOTSYSD_TEST_USER}
	}
	repository hidden.git {
		permit ${GOTSYSD_TEST_USER}
		deny ${GOTSYSD_DEV_USER}
		hide repository on
	}
}
EOF
	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit -m "configure web server" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt unauthorized access.
	w3m "http://${VMIP}/" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Repositories

Log in by running:

ssh ${GOTSYSD_TEST_USER}@${VMIP} "weblogin ${VMIP}"

The SSH host key fingerprints of ${VMIP} are:

ECDSA

    ${GOTSYS_ECDSA_HOST_FP}

ED25519

    ${GOTSYS_ED25519_HOST_FP}

RSA

    ${GOTSYS_RSA_HOST_FP}
    
EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	got init $testroot/testrepo.git
	ret=$?
	if [ $ret -ne 0 ]; then
		"got init failed unexpectedly"
		test_done "$testroot" 1
		return 1
	fi

	mkdir $testroot/import
	echo "my plans are: ..." > $testroot/import/myplans.txt

	got import -m init -r $testroot/testrepo.git $testroot/import > /dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		"got import failed unexpectedly"
		test_done "$testroot" 1
		return 1
	fi

	cat >> $testroot/testrepo.git/got.conf <<EOF
remote "origin" {
	server ${GOTSYSD_TEST_USER}@${VMIP}
	protocol ssh
	repository testrepo
}
EOF

	got send -q -f -i ${GOTSYSD_SSH_KEY} -r $testroot/testrepo.git
	ret=$?
	if [ $ret -ne 0 ]; then
		"got send failed unexpectedly"
		test_done "$testroot" 1
		return 1
	fi

	# Obtain a login token over ssh.
	ssh -q -i ${GOTSYSD_SSH_KEY} ${GOTSYSD_TEST_USER}@${VMIP} \
		'gotsh -c weblogin' > $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "ssh login failed failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Request the index page again using the login token and
	# storing the cookie sent by gotwebd.
	url=$(cut -d: -f 2,3 < $testroot/stdout | sed -e 's/ https:/http:/')
	w3m -cookie-jar "$testroot/cookies" "$url" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories
Repository
testrepo.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Request a tree page using the stored cookie.
	w3m -cookie-jar "$testroot/cookies" \
		"http://${VMIP}/?action=tree&path=testrepo.git" -dump \
		> $testroot/stdout

	local commit_id=`git_show_head $testroot/testrepo.git`
	local commit_time=`git_show_author_time $testroot/testrepo.git $commit_id`
	local d=$(env LC_ALL=C date -u -r "$commit_time" \
		+"%a %b %e %H:%M:%S %Y UTC" | sed -e 's/  / /')
	local tree_id=$(got cat -r $testroot/testrepo.git $commit_id | \
		grep 'tree ' | cut -d ' ' -f2)

	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories / testrepo.git / tree /

Tree

Tree:
    $tree_id
Date:
    $d
Message:
    init

-------------------------------------------------------------------------------

myplans.txt commits | blame

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt to access the same page again without the cookie.
	w3m "http://${VMIP}/?action=tree&path=testrepo.git" -dump \
		> $testroot/stdout

	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`
	local tree_id=$(got cat -r $testroot/${GOTSYS_REPO} $commit_id | \
		grep 'tree ' | cut -d ' ' -f2)

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / testrepo.git / tree /

Log in by running:

ssh ${GOTSYSD_TEST_USER}@${VMIP} "weblogin ${VMIP}"

The SSH host key fingerprints of ${VMIP} are:

ECDSA

    ${GOTSYS_ECDSA_HOST_FP}

ED25519

    ${GOTSYS_ED25519_HOST_FP}

RSA

    ${GOTSYS_RSA_HOST_FP}
    
EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt to access a non-existent repository without the cookie.
	# Observable behaviour should match the case where the name of a
	# hidden and existing repository was guessed correctly.
	w3m "http://${VMIP}/?action=tree&path=nonexistent.git" -dump \
		> $testroot/stdout

	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`
	local tree_id=$(got cat -r $testroot/${GOTSYS_REPO} $commit_id | \
		grep 'tree ' | cut -d ' ' -f2)

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / nonexistent.git / tree /

Log in by running:

ssh ${GOTSYSD_TEST_USER}@${VMIP} "weblogin ${VMIP}"

The SSH host key fingerprints of ${VMIP} are:

ECDSA

    ${GOTSYS_ECDSA_HOST_FP}

ED25519

    ${GOTSYS_ED25519_HOST_FP}

RSA

    ${GOTSYS_RSA_HOST_FP}
    
EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	test_done "$testroot" "0"
}

test_access_rules_index_page() {
	local testroot=`test_init access_rules_index_page 1`

	got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got checkout failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
	crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
	sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
	cat > ${testroot}/wt/gotsys.conf <<EOF
user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
}
repository gotsys.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository public.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottestdev.git {
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottest {
	permit rw ${GOTSYSD_TEST_USER}
}
repository hidden.git {
	permit rw ${GOTSYSD_TEST_USER}
}
web server "${VMIP}" {
	repository public.git {
		disable authentication
	}
	repository gottestdev.git {
		permit ${GOTSYSD_DEV_USER}
		deny ${GOTSYSD_TEST_USER}
	}
	repository gottest.git {
		permit ${GOTSYSD_TEST_USER}
	}
	repository hidden.git {
		permit ${GOTSYSD_TEST_USER}
		deny ${GOTSYSD_DEV_USER}
		hide repository on
	}
}
EOF
	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit \
		-m "add public and gottest repositories" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Request the index page without being logged in.
	# Repositories we do not have access to should not be listed.
	w3m "http://${VMIP}/" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Repositories
Repository
public.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------

EOF

	# Obtain a login token over ssh.
	ssh -q -i ${GOTSYSD_SSH_KEY} ${GOTSYSD_TEST_USER}@${VMIP} \
		'gotsh -c weblogin' > $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "ssh login failed failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Request the index page. Repositories we do not have access
	# to should not be listed.
	url=$(cut -d: -f 2,3 < $testroot/stdout | sed -e 's/ https:/http:/')
	w3m -cookie-jar "$testroot/cookies" "$url" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories
Repository
gottest.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------
public.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Obtain a different login token over ssh.
	ssh -q -i ${GOTSYSD_SSH_KEY} ${GOTSYSD_DEV_USER}@${VMIP} \
		'weblogin' > $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "ssh login failed failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Request the index page. Repositories we do not have access
	# to should not be listed.
	url=$(cut -d: -f 2,3 < $testroot/stdout | sed -e 's/ https:/http:/')
	w3m -cookie-jar "$testroot/cookies" "$url" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_DEV_USER}  (Logout)
Repositories
Repository
gottestdev.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------
public.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi
	test_done "$testroot" "0"
}

test_access_rules_tree_page() {
	local testroot=`test_init access_rules_tree_page 1`

	GOTSYS_ECDSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub | \
		cut -d' ' -f2)
	GOTSYS_ED25519_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub | \
		cut -d' ' -f2)
	GOTSYS_RSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub | \
		cut -d' ' -f2)

	got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got checkout failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
	crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
	sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
	cat > ${testroot}/wt/gotsys.conf <<EOF
user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
}
repository gotsys.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository public.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottestdev.git {
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottest.git {
	permit rw ${GOTSYSD_TEST_USER}
}
repository hidden.git {
	permit rw ${GOTSYSD_TEST_USER}
}
web server "${VMIP}" {
	repository public {
		disable authentication
	}
	repository gottestdev.git {
		permit ${GOTSYSD_DEV_USER}
		deny ${GOTSYSD_TEST_USER}
	}
	repository gottest.git {
		permit ${GOTSYSD_TEST_USER}
	}
	repository hidden {
		permit ${GOTSYSD_TEST_USER}
		deny ${GOTSYSD_DEV_USER}
		hide repository on
	}
}
EOF
	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit -m "no-op update" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt to access a public repository's tree
	w3m "http://${VMIP}/?action=tree&path=public.git" -dump \
		> $testroot/stdout

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / public.git / tree /
reference refs/heads/main not found

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt to access a private repository's tree
	w3m "http://${VMIP}/?action=tree&path=gottest.git" -dump \
		> $testroot/stdout

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / gottest.git / tree /

Log in by running:

ssh ${GOTSYSD_TEST_USER}@${VMIP} "weblogin ${VMIP}"

The SSH host key fingerprints of ${VMIP} are:

ECDSA

    ${GOTSYS_ECDSA_HOST_FP}

ED25519

    ${GOTSYS_ED25519_HOST_FP}

RSA

    ${GOTSYS_RSA_HOST_FP}
    
EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Obtain a login token over ssh.
	ssh -q -i ${GOTSYSD_SSH_KEY} ${GOTSYSD_TEST_USER}@${VMIP} \
		'gotsh -c weblogin' > $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "ssh login failed failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	url=$(cut -d: -f 2,3 < $testroot/stdout | sed -e 's/ https:/http:/')
	w3m -cookie-jar "$testroot/cookies" "$url" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories
Repository
gottest.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------
public.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt to access the private repository's tree again with cookie
	w3m -cookie-jar $testroot/cookies \
		"http://${VMIP}/?action=tree&path=gottest.git" -dump \
		> $testroot/stdout

	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories / gottest.git / tree /
reference refs/heads/main not found

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Test authentication via group membership.
	crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
	crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
	sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
	cat > ${testroot}/wt/gotsys.conf <<EOF
group writers
group devs
group testers

user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
	group writers
	group testers
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
	group writers
	group devs
}
repository gotsys.git {
	permit rw :writers
}
repository public.git {
	permit rw :writers
}
repository gottestdev.git {
	permit rw :devs
}
repository gottest.git {
	permit rw :testers
}
repository hidden.git {
	permit rw :testers
}
web server "${VMIP}" {
	repository public {
		disable authentication
	}
	repository gottestdev.git {
		permit :devs
		deny :testers
	}
	repository gottest.git {
		permit :testers
	}
	repository hidden {
		permit :testers
		deny :devs
		hide repository on
	}
}
EOF
	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit -m "use group auth" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Obtain a login token over ssh.
	ssh -q -i ${GOTSYSD_SSH_KEY} ${GOTSYSD_TEST_USER}@${VMIP} \
		'gotsh -c weblogin' > $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "ssh login failed failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	url=$(cut -d: -f 2,3 < $testroot/stdout | sed -e 's/ https:/http:/')
	w3m -cookie-jar "$testroot/cookies" "$url" -dump > $testroot/stdout
	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories
Repository
gottest.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------
public.git
summary | briefs | commits | tags | tree | rss
-------------------------------------------------------------------------------

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Attempt to access the private repository's tree again with cookie
	w3m -cookie-jar $testroot/cookies \
		"http://${VMIP}/?action=tree&path=gottest.git" -dump \
		> $testroot/stdout

	cat > $testroot/stdout.expected <<EOF
[got]
Logged in as: ${GOTSYSD_TEST_USER}  (Logout)
Repositories / gottest.git / tree /
reference refs/heads/main not found

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	test_done "$testroot" "$ret"
}

test_summary_page() {
	local testroot=`test_init summary_page 1`

	GOTSYS_ECDSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub | \
		cut -d' ' -f2)
	GOTSYS_ED25519_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub | \
		cut -d' ' -f2)
	GOTSYS_RSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub | \
		cut -d' ' -f2)

	got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got checkout failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
	crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
	sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
	cat > ${testroot}/wt/gotsys.conf <<EOF
user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
}
repository gotsys.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository public.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottestdev.git {
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottest.git {
	permit rw ${GOTSYSD_TEST_USER}
}
repository hidden.git {
	permit rw ${GOTSYSD_TEST_USER}
}
web server "${VMIP}" {
	repository public {
		disable authentication
	}
	repository gottestdev.git {
		permit ${GOTSYSD_DEV_USER}
		deny ${GOTSYSD_TEST_USER}
	}
	repository gottest.git {
		permit ${GOTSYSD_TEST_USER}
	}
	repository hidden {
		permit ${GOTSYSD_TEST_USER}
		deny ${GOTSYSD_DEV_USER}
		hide repository on
	}
}
EOF
	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit -m "no-op change" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	got init $testroot/public.git > /dev/null
	mkdir -p $testroot/public

	cat > $testroot/public/readme.txt <<EOF
Testing the summary page of gotwebd
EOF
	got import -m init -r $testroot/public.git $testroot/public > /dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got import failed unexpectedly" >&2
		return 1
	fi
	local commit_id=`git_show_head $testroot/public.git`
	local short_commit_id=`trim_obj_id 10 $commit_id`

	cat > $testroot/public.git/got.conf <<EOF
remote "origin" {
	server "${GOTSYSD_DEV_USER}@$VMIP"
	protocol ssh
	repository "public"
}
EOF
	got send -q -i ${GOTSYSD_SSH_KEY} -b main -f -r $testroot/public.git
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		return 1
	fi

	# Attempt to access a public repository's summary
	w3m "http://${VMIP}/?action=summary&path=public.git" -dump \
		> $testroot/stdout

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / public.git / summary

Clone URL:

    ssh://${GOTSYSD_TEST_USER}@${VMIP}/public.git

ECDSA:

    ${GOTSYS_ECDSA_HOST_FP}

ED25519:

    ${GOTSYS_ED25519_HOST_FP}

RSA:

    ${GOTSYS_RSA_HOST_FP}

Commit Briefs

right now $short_commit_id Flan Hacker

init (main)

diff | patch | tree
-------------------------------------------------------------------------------

Branches

right now
main
summary | commit briefs | commits
-------------------------------------------------------------------------------

Tags

This repository contains no tags

Tree

readme.txt commits | blame

readme.txt

Testing the summary page of gotwebd

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	# Test the case where a repository inherits default setings
	# without being mentioned in the web server block.
	cat > ${testroot}/wt/gotsys.conf <<EOF
user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
}
repository gotsys.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository public.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottestdev.git {
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottest.git {
	permit rw ${GOTSYSD_TEST_USER}
}
repository hidden.git {
	permit rw ${GOTSYSD_TEST_USER}
}
web server "${VMIP}" {
	disable authentication
}
EOF
	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit -m "no-op change" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	got checkout -E -q $testroot/public.git $testroot/public > /dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got checkout failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	cat > $testroot/public/readme.txt <<EOF
Testing the summary page of gotwebd again
EOF
	(cd ${testroot}/public && got commit -m "tweak" >/dev/null)
	local commit_id=`git_show_head $testroot/public.git`
	local short_commit_id=`trim_obj_id 10 $commit_id`

	got send -q -i ${GOTSYSD_SSH_KEY} -b main -f -r $testroot/public.git
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		return 1
	fi

	# Attempt to access a public repository's summary
	w3m "http://${VMIP}/?action=summary&path=public.git" -dump \
		> $testroot/stdout

	grep -v 'seconds ago' $testroot/stdout > $testroot/stdout.filtered

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / public.git / summary

Clone URL:

    ssh://${GOTSYSD_TEST_USER}@${VMIP}/public.git

ECDSA:

    ${GOTSYS_ECDSA_HOST_FP}

ED25519:

    ${GOTSYS_ED25519_HOST_FP}

RSA:

    ${GOTSYS_RSA_HOST_FP}

Commit Briefs

right now $short_commit_id Flan Hacker

tweak (main)

diff | patch | tree
-------------------------------------------------------------------------------


init

diff | patch | tree
-------------------------------------------------------------------------------

Branches

right now
main
summary | commit briefs | commits
-------------------------------------------------------------------------------

Tags

This repository contains no tags

Tree

readme.txt commits | blame

readme.txt

Testing the summary page of gotwebd again

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout.filtered
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout.filtered
		test_done "$testroot" "$ret"
		return 1
	fi
	test_done "$testroot" "$ret"
}

test_utf8_site_owner() {
	local testroot=`test_init utf8_site_owner 1`

	GOTSYS_ECDSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub | \
		cut -d' ' -f2)
	GOTSYS_ED25519_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub | \
		cut -d' ' -f2)
	GOTSYS_RSA_HOST_FP=$(ssh -i ${GOTSYSD_SSH_KEY} \
		${GOTSYSD_TEST_USER}@${VMIP} \
		ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub | \
		cut -d' ' -f2)

	got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got checkout failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'`
	crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'`
	sshkey=`cat ${GOTSYSD_SSH_PUBKEY}`
	cat > ${testroot}/wt/gotsys.conf <<EOF
user ${GOTSYSD_TEST_USER} {
	password "${crypted_vm_pw}" 
	authorized key ${sshkey}
}
user ${GOTSYSD_DEV_USER} {
	password "${crypted_pw}" 
	authorized key ${sshkey}
}
repository gotsys.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository public.git {
	permit rw ${GOTSYSD_TEST_USER}
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottestdev.git {
	permit rw ${GOTSYSD_DEV_USER}
}
repository gottest.git {
	permit rw ${GOTSYSD_TEST_USER}
}
repository hidden.git {
	permit rw ${GOTSYSD_TEST_USER}
}
web server "${VMIP}" {
	repository public {
		disable authentication
	}
	repository gottestdev.git {
		permit ${GOTSYSD_DEV_USER}
		deny ${GOTSYSD_TEST_USER}
	}
	repository gottest.git {
		permit ${GOTSYSD_TEST_USER}
	}
	repository hidden {
		permit ${GOTSYSD_TEST_USER}
		deny ${GOTSYSD_DEV_USER}
		hide repository on
	}
EOF
	cp  ${testroot}/wt/gotsys.conf ${testroot}/wt/gotsys.conf.bad

	# "honey bear" in German, in UTF-8 encoding
	printf '\tsite owner "Honigb\xc3\xa4r"\n' >> ${testroot}/wt/gotsys.conf

	# "honey bear" in German, in Latin1 encoding
	printf '\tsite owner "Honigb\xe4r"\n' >> ${testroot}/wt/gotsys.conf.bad

	printf '}\n' >> ${testroot}/wt/gotsys.conf.bad
	printf '}\n' >> ${testroot}/wt/gotsys.conf

	(cd ${testroot}/wt && gotsys check -q \
		-f ${testroot}/wt/gotsys.conf.bad 2> ${testroot}/stderr)
	ret=$?
	if [ $ret -eq 0 ]; then
		echo "bad gotsys.conf accepted by gotsys check" >&2
		test_done "$testroot" 1
		return 1
	fi
	cat > $testroot/stderr.expected <<EOF
gotsys: ${testroot}/wt/gotsys.conf.bad: line 42: invalid UTF-8 string
EOF
	cmp -s $testroot/stderr.expected $testroot/stderr
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stderr.expected $testroot/stderr
		test_done "$testroot" "$ret"
		return 1
	fi

	(cd ${testroot}/wt && gotsys check -q)
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "bad gotsys.conf written by test" >&2
		test_done "$testroot" 1
		return 1
	fi

	(cd ${testroot}/wt && got commit -m "add UTF-8 strings" >/dev/null)
	local commit_id=`git_show_head $testroot/${GOTSYS_REPO}`

	got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO}
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		test_done "$testroot" 1
		return 1
	fi

	# Wait for gotsysd to apply the new configuration.
	echo "$commit_id" > $testroot/stdout.expected
	for i in 1 2 3 4 5; do
		sleep 1
		ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \
			cat /var/db/gotsysd/commit > $testroot/stdout
		if cmp -s $testroot/stdout.expected $testroot/stdout; then
			break;
		fi
	done
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "gotsysd failed to apply configuration" >&2
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	got init $testroot/public.git > /dev/null
	mkdir -p $testroot/public

	cat > $testroot/public/readme.txt <<EOF
Testing the summary page of gotwebd
EOF
	got import -m init -r $testroot/public.git $testroot/public > /dev/null
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got import failed unexpectedly" >&2
		return 1
	fi
	local commit_id=`git_show_head $testroot/public.git`
	local short_commit_id=`trim_obj_id 10 $commit_id`

	cat > $testroot/public.git/got.conf <<EOF
remote "origin" {
	server "${GOTSYSD_DEV_USER}@$VMIP"
	protocol ssh
	repository "public"
}
EOF
	got send -q -i ${GOTSYSD_SSH_KEY} -b main -f -r $testroot/public.git
	ret=$?
	if [ $ret -ne 0 ]; then
		echo "got send failed unexpectedly" >&2
		return 1
	fi

	# Attempt to access a public repository's summary
	w3m -O UTF-8 "http://${VMIP}/?action=summary&path=public.git" -dump \
		> $testroot/stdout

	cat > $testroot/stdout.expected <<EOF
[got]
Repositories / public.git / summary

Clone URL:

    ssh://${GOTSYSD_TEST_USER}@${VMIP}/public.git

ECDSA:

    ${GOTSYS_ECDSA_HOST_FP}

ED25519:

    ${GOTSYS_ED25519_HOST_FP}

RSA:

    ${GOTSYS_RSA_HOST_FP}

Commit Briefs

right now $short_commit_id Flan Hacker

init (main)

diff | patch | tree
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Branches

right now
main
summary | commit briefs | commits
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Tags

This repository contains no tags

Tree

readme.txt commits | blame

readme.txt

Testing the summary page of gotwebd

Honigbär

EOF
	cmp -s $testroot/stdout.expected $testroot/stdout
	ret=$?
	if [ $ret -ne 0 ]; then
		diff -u $testroot/stdout.expected $testroot/stdout
		test_done "$testroot" "$ret"
		return 1
	fi

	test_done "$testroot" "$ret"
}

test_parseargs "$@"
run_test test_login
run_test test_access_rules_index_page
run_test test_access_rules_tree_page
run_test test_summary_page
run_test test_utf8_site_owner
