#!/bin/sh

# condor_docker_pat producer -- a script to generate and store
# a docker Personal Access Token (PAT) to send to an EP to 
# use to access protected docker images.
#
emit_error() {
MESSAGE=$1
echo    '{'
echo -n '"HTCondorError":'
echo "\"$MESSAGE\""
echo    '}'
}

# Get the Docker credentials from config.json
DOCKER_CONFIG="$HOME/.docker/config.json"

# Where the cached PAT will live 
PAT_FILE="$HOME/.docker/htcondor_pat.json"

if [ ! -f "$DOCKER_CONFIG" ]; then
    emit_error "Docker config.json not found at $DOCKER_CONFIG"
    exit 1
fi

# if we have a saved pat that is newer than the config, just emit that
if [ "$PAT_FILE" -nt "$DOCKER_CONFIG" ]; then
	cat $PAT_FILE
	exit 0
fi

# Get the username + password credentials that docker login generated
DOCKER_AUTH=$(jq -r '.auths["https://index.docker.io/v1/"].auth' "$DOCKER_CONFIG" | base64 -d)

# Split out the  username and password (which might be a token, not a password)
DOCKER_USERNAME=$(echo "$DOCKER_AUTH" | cut -d':' -f1)
DOCKER_PASSWORD=$(echo "$DOCKER_AUTH" | cut -d':' -f2)

if [ -z "$DOCKER_USERNAME" ] || [ -z "$DOCKER_PASSWORD" ]; then
    emit_error "Could not extract Docker Hub credentials. Ensure you are logged in using docker login"
    exit 1
fi

# now get a bearer token from docker hub
BEARER_TOKEN=$(curl -s -X POST "https://hub.docker.com/v2/users/login/" \
    -H "Content-Type: application/json" \
    -d "{\"username\": \"$DOCKER_USERNAME\", \"password\": \"$DOCKER_PASSWORD\"}" | jq -r '.token')

if [ "$BEARER_TOKEN" == "null" ] || [ -z "$BEARER_TOKEN" ]; then
    emit_error "Failed to retrieve bearer token."
    exit 1
fi

# Help the user figure out what schedd requested this token
# when they look at the web form
HOSTNAME=$(hostname)
PAT_NAME="HTCondor autogenerated PAT on $HOSTNAME"

# Finally, generate a read-only Personal Access Token (PAT)
PAT_RESPONSE=$(curl -s -X POST "https://hub.docker.com/v2/access-tokens/" \
    -H "Authorization: Bearer $BEARER_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"token_label\": \"$PAT_NAME\", \"expires_at\": null, \"scopes\": [ \"repo:read\" ] }")

# Extract the PAT from the response
PAT=$(echo "$PAT_RESPONSE" | jq -r '.token')

if [ "$PAT" == "null" ] || [ -z "$PAT" ]; then
    emit_error "Failed to generate PAT."
    exit 1
fi

# Extract the UUID from the response
UUID=$(echo "$PAT_RESPONSE" | jq -r '.uuid')

# Docker looks for an "auths" attribute which is username:pat, all base64 encoded
DOCKER_AUTHS=$(echo -n "${DOCKER_USERNAME}:${PAT}" | base64 -w 0)

# roll the new file in atomically
# Docker doesn't need the uuid field, but we need it to delete
# the token later.
(
echo '{'
echo    '	"auths": {'
echo    '		"https://index.docker.io/v1/": {'
echo    "			\"auth\": \"$DOCKER_AUTHS\"",
echo    "			\"uuid\": \"$UUID\""
echo	'		}'
echo '	}'
echo '}'
) > "$PAT_FILE".tmp

chmod 600 "$PAT_FILE".tmp
mv "$PAT_FILE".tmp "$PAT_FILE"

# and emit the token in the form of a docker json config file suitable for
# ingestion into docker
cat $PAT_FILE
exit 0
