pass-gocrypt/gocrypt.bash

176 lines
5.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-only
# Copyright (C) 2022 Peter Cai <peter at typeblog dot net>
readonly gocrypt_dir=".gocrypt"
readonly gocrypt_dec_dir="gocrypt"
readonly gocrypt_passwd_file="gocrypt-passwd"
gocrypt_sys_check() {
which gocryptfs > /dev/null || gocrypt_die "gocryptfs not found in PATH"
}
gocrypt_env_check() {
gocrypt_sys_check
[ ! -d "$gocrypt_dir" ] && gocrypt_die "gocrypt plugin not initialized"
}
gocrypt_close_check() {
gocrypt_env_check
[ -f "$gocrypt_dec_dir"/.pass-gocrypt ] && gocrypt_die "gocrypt already opened"
}
gocrypt_open_check() {
gocrypt_env_check
[ ! -f "$gocrypt_dec_dir"/.pass-gocrypt ] && gocrypt_die "gocrypt not opened"
}
gocrypt_die() {
printf "Error: %s\n" "$1" >&2
exit 1
}
gocrypt_init() {
gocrypt_sys_check
if [ -d "$gocrypt_dir" ] || [ -f "$gocrypt_dir" ]; then
gocrypt_die "gocrypt plugin already initialized for your password store"
fi
pass generate "$gocrypt_passwd_file" 32
# Initialize gocryptfs
mkdir "$gocrypt_dir"
gocryptfs -passfile /dev/stdin -init "$gocrypt_dir" <<< "$(pass show "$gocrypt_passwd_file")"
# Mount the gocryptfs subdirectory and initialze what is inside of it
gocrypt_open
touch "$gocrypt_dec_dir"/.pass-gocrypt
# By default, we use the same gpg-id inside, but the user can decide to use a different one later by doing it manually
ln -s ../.gpg-id "$gocrypt_dec_dir"/.gpg-id
# Add the decrypted path to gitignore
echo >> .gitignore
echo "# Gocrypt" >> .gitignore
echo "gocrypt" >> .gitignore
pass git add .gitignore
pass git add "$gocrypt_dir"
pass git commit -m "Initialized encrypted storage for gocrypt plugin"
}
gocrypt_open() {
gocrypt_close_check
mkdir -p "$gocrypt_dec_dir"
gocryptfs -passfile /dev/stdin "$gocrypt_dir" "$gocrypt_dec_dir" <<< "$(pass show "$gocrypt_passwd_file")"
}
gocrypt_close() {
gocrypt_open_check
fusermount -u "$gocrypt_dec_dir"
}
gocrypt_delegate() {
gocrypt_open_check
# Delegate command to another `pass` instance that manages what is inside of the mountpoint
PASSWORD_STORE_DIR="$PWD/$gocrypt_dec_dir" pass "$@"
# Commit if there has been changes due to this operation
pass git add "$gocrypt_dir"
pass git commit -m "Encrypted pass operation inside gocrypt" "$gocrypt_dir" || echo "No git commit created"
}
gocrypt_crypt() {
gocrypt_open_check
[ ! -f "$1.gpg" ] && gocrypt_die "Not found: $1"
cmd_show "$1" | EDITOR=tee gocrypt_delegate edit "$1"
cmd_delete -f "$1"
echo "Moved $1 into encrypted storage"
}
gocrypt_help() {
printf "%s" "\
$PROGRAM gocrypt - hide part of the password store in a subdirectory encrypted with gocryptfs
usage
$PROGRAM gocrypt init
Initialize a encrypted subdirectory at \$PASSWORD_STORE_DIR/$gocrypt_dir. The password used by
gocryptfs will be generated by pass and stored at \$PASSWORD_STORE_DIR/$gocrypt_passwd_file.gpg.
The encrypted subdirectory, along with the generated (encrypted) password, will be committed to
the git repository managed by pass, if there is one.
By default, the .gpg-id file of the main password store will be symlinked into the encrypted
subtree. You can change this manually by mounting (opening) the directory and replacing this
symlink with a custom one.
$PROGRAM gocrypt open
Mount the encrypted subdirectory to \$PASSWORD_STORE_DIR/$gocrypt_dec_dir.
$PROGRAM gocrypt close
Unmount the encrypted subtree, if it was opened before.
$PROGRAM gocrypt crypt <pass_name>
Move a password <pass_name> from the original password store to the encrypted subdirectory. Note
that if you use git, this will still leave a record in the git repository of the original password
store.
$PROGRAM gocrypt help
Print this help message.
$PROGRAM gocrypt [ls|list|grep|find|search|show|insert|add|edit|generate|rm|remove|delete|mv|rename|cp|copy|git] ...
Run the provided subcommand of pass inside the encrypted subtree. This requires that the subdirectory
has been mounted. When the operation is completed, if the outer password store is a git repository, a
new commit will be created containing all the encrypted modifications done by the command inside the
subtree. The commit message will be a generic one and will not leak content inside the subtree.
You should *always* use this command when modifying the encrypted subtree. If your password store is a
git repository, operating inside a subtree behind a mountpoint (which is created by gocryptfs) will not
work properly, and may leak metadata inside the mountpoint.
TIP: You can create a nested git repository inside the encrypted subtree using \`$PROGRAM gocrypt git ...\`
commands. This way, any modification in the encrypted subtree will be tracked *both* inside and outside,
such that the commit inside will contain actual metadata about the modification, and the one outside will be
encrypted. You will only need to push the repository outside for backup purposes.
"
}
if [ $# -eq 0 ]; then
gocrypt_help
exit 1
fi
if [ ! -d "$PREFIX" ]; then
gocrypt_die "Cannot open password store"
fi
# cd into the password store prefix
cd "$PREFIX"
case "$1" in
help)
gocrypt_help
exit 0
;;
init)
shift
gocrypt_init "$@"
;;
open)
shift
gocrypt_open "$@"
;;
crypt)
shift
gocrypt_crypt "$@"
;;
close)
shift
gocrypt_close "$@"
;;
ls|list|grep|find|search|show|insert|add|edit|generate|rm|remove|delete|mv|rename|cp|copy|git)
# No shift here since we need to delegate these commands to another pass instance
gocrypt_delegate "$@"
;;
*)
gocrypt_die "Unknown command $1 for gocrypt"
esac