Skip to content

Instantly share code, notes, and snippets.

@fuhry
Last active December 12, 2022 20:36
Show Gist options
  • Save fuhry/ef95907857fec09fc1e0f0baa4429452 to your computer and use it in GitHub Desktop.
Save fuhry/ef95907857fec09fc1e0f0baa4429452 to your computer and use it in GitHub Desktop.
git-credential helper for zx2c4's passwordstore
#!/bin/bash
# Git credential helper for pass(1) (https://passwordstore.org/).
# To set up, first install this script into your PATH with the name `git-credential-pass`.
# Then, you will need to create a credential map file (see below) within your pass repository.
# Finally, configure git as follows:
#
# git config credential.helper pass
# git config credential.useHttpPath true
# The `pass` path to your credential map. The format is described below. Typing
# `pass ${CREDENTIAL_MAP_PASSOBJ}` at a shell should output the credential map
# to standard output.
CREDENTIAL_MAP_PASSOBJ=Websites/github.com/CredentialMap
# The format of the credential map is as follows:
# protocol <TAB> host <TAB> path <TAB> pass_object
#
# For example:
# https github.com someuser/somerepo.git Websites/github.com/PersonalAccessToken/someuser
#
# It's permitted to use `.*` in the "path" portion to match any substring. The default input
# validation in this script is rather strict, but you may modify the regular expressions
# below to allow for more complex regexps in the path if you desire.
#
# The password file must be formatted as follows:
#
# username=foo
# password=bar
#
# Lines that do not begin with "username=" or "password=" will not be printed back to git.
declare -r CREDENTIAL_PROTOCOL_REGEXP="[a-z]+"
declare -r CREDENTIAL_HOST_REGEXP="[a-z0-9-]+(\\.[a-z0-9-]+)*"
declare -r CREDENTIAL_PATH_REGEXP="[A-Za-z0-9_\\.\\*-]+(/[A-Za-z0-9\\.\\*_-]+)*"
declare -r CREDENTIAL_PASSOBJ_REGEXP="[A-Za-z0-9_-]+(/[A-Za-z0-9_-]+)*"
declare -r CREDENTIAL_LINE_REGEXP="^${CREDENTIAL_PROTOCOL_REGEXP}\\t${CREDENTIAL_HOST_REGEXP}\\t${CREDENTIAL_PATH_REGEXP}\\t${CREDENTIAL_PASSOBJ_REGEXP}$"
case "$1" in
get)
protocol=
host=
path=
while read line; do
if [[ "$line" =~ ^protocol=(${CREDENTIAL_PROTOCOL_REGEXP})$ ]]; then
protocol="${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^host=(${CREDENTIAL_HOST_REGEXP})$ ]]; then
host="${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^path=(${CREDENTIAL_PATH_REGEXP})$ ]]; then
path="${BASH_REMATCH[1]}"
else
echo "Invalid input line: $line" >&2
exit 1
fi
done
for v in protocol host path; do
if [ -z "${!v}" ]; then
echo "Invalid input: '$v' was not set" >&2
exit 1
fi
done
while read line; do
IFS="$(echo -en "\t")" read line_protocol line_host line_repo_regexp cred_name <<< "$line"
if [ "$protocol" = "$line_protocol" -a "$host" = "$line_host" ]; then
if [[ "$path" =~ ^${line_repo_regexp}$ ]]; then
pass "${cred_name}" | grep -E '^(username|password)=' && exit 0
fi
fi
done < <(pass "${CREDENTIAL_MAP_PASSOBJ}" | grep -Px "${CREDENTIAL_LINE_REGEXP}")
echo "$0: No match found for protocol=${protocol} host=${host} path=${path}" >&2
exit 2
;;
store|erase)
# Not implemented.
echo "The action '$1' is not implemented." >&2
exit 1
;;
*)
echo "Usage: $0 (get|store|erase)" >&2
echo 'See `man 1 git-credential` for details.' >&2
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment