#!/bin/bash
# MIT License
#
# Copyright (c) 2023 SySS Research, Adrian Vollmer
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
set -uo pipefail

PORT="${PORT:-8181}"
WORKSPACE="${WORKSPACE:-default}"
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/BloodHound-CE/$WORKSPACE"
NEO4J_VOL="$DATA_DIR/neo4j"
POSTGRES_VOL="$DATA_DIR/postgres"
NETWORK="BloodHound-CE-network"

BLOODHOUND_ADMIN_NAME="admin"
BLOODHOUND_ADMIN_PASSWORD="admin"

BLOODHOUND_IMAGE="docker.io/specterops/bloodhound:${BLOODHOUND_TAG:-latest}"
NEO4J_IMAGE="docker.io/library/neo4j:4.4"
POSTGRES_IMAGE="docker.io/library/postgres:16"

BLOODHOUND_CONTAINER="BloodHound-CE_BH"
NEO4J_CONTAINER="BloodHound-CE_Neo4j"
POSTGRES_CONTAINER="BloodHound-CE_PSQL"

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

mkdir -p "$DATA_DIR"
mkdir -p "$NEO4J_VOL"
mkdir -p "$POSTGRES_VOL"

if [ "${1:-}" = 'pull' ]; then
	podman pull "$BLOODHOUND_IMAGE"
	podman pull "$NEO4J_IMAGE"
	podman pull "$POSTGRES_IMAGE"
	exit
fi

finish() {
	result=$?
	echo Stopping containers ...
	#  podman stop -i "${BLOODHOUND_CONTAINER}" > /dev/null
	podman stop -i "${NEO4J_CONTAINER}" >/dev/null
	podman stop -i "${POSTGRES_CONTAINER}" >/dev/null
	exit ${result}
}
trap finish EXIT

podman network exists "$NETWORK" || podman network create "$NETWORK"

TIMESTAMP="$(date +%s)"

function run_postgres() {
	echo Running postgres container ... &&
		podman run \
			--rm \
			--replace \
			--detach \
			--net "$NETWORK" \
			--network-alias app-db \
			--name "$POSTGRES_CONTAINER" \
			--volume "$POSTGRES_VOL":/var/lib/postgresql/data \
			-e PGUSER=bloodhound \
			-e POSTGRES_USER=bloodhound \
			-e POSTGRES_PASSWORD=bloodhoundcommunityedition \
			-e POSTGRES_DB=bloodhound \
			"$POSTGRES_IMAGE" \
			>/dev/null
}

function run_neo4j() {
	echo Running neo4j container ... &&
		podman run \
			--rm \
			--detach \
			--replace \
			--net "$NETWORK" \
			--network-alias graph-db \
			--name "$NEO4J_CONTAINER" \
			--volume "$NEO4J_VOL":/data \
			--publish 127.0.0.1:7474:7474 \
			--publish 127.0.0.1:7687:7687 \
			-e "NEO4J_AUTH=neo4j/bloodhoundcommunityedition" \
			"$NEO4J_IMAGE" \
			>/dev/null
}

function run_bloodhound() {
	echo Running bloodhound container ... &&
		podman run \
			--rm \
			--replace \
			--detach \
			--net "$NETWORK" \
			--network-alias bloodhound \
			--name "$BLOODHOUND_CONTAINER" \
			--publish 127.0.0.1:"${PORT}":8080 \
			-e bhe_disable_cypher_qc="${bhe_disable_cypher_qc:-false}" \
			-e bhe_database_connection="user=bloodhound password=bloodhoundcommunityedition dbname=bloodhound host=app-db" \
			-e bhe_neo4j_connection="neo4j://neo4j:bloodhoundcommunityedition@graph-db:7687/" \
			-e bhe_default_admin_principal_name="$BLOODHOUND_ADMIN_NAME" \
			-e bhe_default_admin_password="$BLOODHOUND_ADMIN_PASSWORD" \
			"$BLOODHOUND_IMAGE" \
			>/dev/null
}

run_postgres
run_neo4j

# Not waiting for postgres because it's faster than neo4j anyway.

echo Wait until neo4j is ready ...
while true; do
	sleep 1
	LOG="$(podman logs --since "$TIMESTAMP" "$NEO4J_CONTAINER" 2>&1)"
	echo "${LOG}" | grep -q "Remote interface available at http://localhost:7474/" && break
	if (echo "${LOG}" | grep -E 'Error'); then
		echo "${LOG}"
		printf "${RED}Neo4j container failed${NC}\n"
		exit 1
	fi
done

run_bloodhound

echo Wait until bloodhound is ready ...
while true; do
	sleep 1
	LOG="$(podman logs --since "$TIMESTAMP" "$BLOODHOUND_CONTAINER" 2>&1)"
	(echo "${LOG}" | grep -q "Server started successfully") && break
	if (echo "${LOG}" | grep -qE '^(\{"level":"(error|fatal)")|(Error: )'); then
		echo "${LOG}"
		printf "${RED}BloodHound container failed${NC}\n"
		exit 1
	fi
done

# Avoid having to choose a new password
EXPIRY="$(date -I -d 1year) 00:00:00+00"
podman exec "$POSTGRES_CONTAINER" psql -q -U "bloodhound" -d "bloodhound" -c \
	"UPDATE auth_secrets SET expires_at='$EXPIRY' WHERE id='1';"

printf "${GREEN}Success! Go to http://localhost:$PORT${NC}\n"
printf "${GREEN}Login with ${BLOODHOUND_ADMIN_NAME}/${BLOODHOUND_ADMIN_PASSWORD}${NC}\n"
echo "Workspace: ${WORKSPACE}"
echo "Press CTRL-C when you're done."

podman logs --since "$TIMESTAMP" "$BLOODHOUND_CONTAINER"
podman attach "$BLOODHOUND_CONTAINER" | grep --color -E 'error|Initial Password Set To:|$'
