Skip to content

Instantly share code, notes, and snippets.

@yesmar
Last active January 27, 2018 00:52
Show Gist options
  • Save yesmar/0a3bd70007cf05887c48a6f5fc4e637f to your computer and use it in GitHub Desktop.
Save yesmar/0a3bd70007cf05887c48a6f5fc4e637f to your computer and use it in GitHub Desktop.
Encrypted disk image on/off switch for macOS
#!/bin/bash
# gknox.bash: encrypted disk image on/off switch for macOS
# Copyright © 2015,2017, Ramsey Dow. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause
PERSONAL_BIN=~/.local/bin
PATH=${PERSONAL_BIN}:/bin:/usr/bin:/usr/sbin
script=$(basename "$0")
rcfile=~/.${script}rc
verbose=/dev/null
function usage {
cat << FOO
Usage: $script [options]
-h Displays this help text.
-i <pathname> Pathname of the disk image to mount.
-m <mountpoint> Where to mount the disk image.
-v Run in verbose mode.
Default values for the pathname and mountpoint can be defined in
~/$(basename "$rcfile") as image=<pathname> and mountpoint=<mountpoint>.
Comments must appear in the first column. Inline comments are not
supported at this time.
FOO
exit 1
}
function load_defaults {
local __image=$1
local __mountpoint=$2
if [ -f "$rcfile" ] && [ -r "$rcfile" ]; then
while read -r line; do
first_char=${line:0:1}
if [ "$first_char" != '#' ]; then
name=$(echo "$line" | cut -d= -f1 )
value=$(echo "$line" | cut -d= -f2 )
case $name in
image) default_image=$value;;
mountpoint) default_mountpoint=$value;;
esac
fi
done < "$rcfile"
if [[ "$__image" ]]; then
eval "$__image"="$default_image"
fi
if [[ "$__mountpoint" ]]; then
eval "$__mountpoint"="$default_mountpoint"
fi
fi
}
function mount_image {
local __image=$1
local __volume=$2
local __mountpoint=$3
local __verbose=$4
local __status=$5
diskutil list "$__volume" &>/dev/null
if (($? == 1)); then
hdiutil attach "$1" -mountpoint "$__mountpoint" &>/dev/null
status=$?
if ((status == 0)); then
echo mounted "$(basename "$__image")" to "$__mountpoint" >&"$__verbose"
fi
else
hdiutil detach -force "$__mountpoint" &>/dev/null
status=$?
if ((status == 0)); then
echo unmounted "$__mountpoint" >&"$__verbose"
fi
fi
if [[ "$__status" ]]; then
eval "$__status"="$status"
fi
}
# shellcheck disable=SC2154
if (("$(uname -s)" != "Darwin")); then
echo "$script": sorry, this script is for macOS. dang.
exit 1
fi
load_defaults image mountpoint
if [ "$image" != "" ]; then
volume=$(basename "${image%%.*}")
fi
while getopts :hi:m:v opt; do
case $opt in
h) usage;;
i) image="$OPTARG"
volume=$(basename "${image%%.*}");;
m) mountpoint="$OPTARG";;
v) verbose=1;; # That's a file descriptor, not a Boolean!
--) break;;
:) echo "$script": option -"$OPTARG" requires an argument. >&2
exit 1;;
\?) echo "$script": invalid option: -"$OPTAR"G >&2
exit 1;;
esac
done
shift $((OPTIND-1))
if (($# > 0)); then
usage
fi
if [[ ($image == "" || $mountpoint == "") ]]; then
echo "$script": please specify both image and mountpoint
exit 1
fi
if [ ! -e "$image" ]; then
echo "$script": "$image": not found
exit 1
fi
if [ ! -d "$mountpoint" ]; then
echo "$script": "mountpoint": must be a directory
exit 1
fi
mount_image "$image" "$volume" "$mountpoint" "$verbose" status
exit $status
@yesmar
Copy link
Author

yesmar commented Feb 4, 2017

The gknox script is for macOS users who want to quickly mount/unmount an encrypted disk image. It works like an on/off switch. The image can be a disk image or sparse bundle. I wrote this script to automate the process of mounting an encrypted signing keys volume on top of my existing ~/.gnupg directory, which is usually just filled with boring public keys for software I like to use.

Call me paranoid, but I don't like leaving signing keys lying around in my ~/.gnupg directory, even if the secret key is encrypted. I don't even want you to see that I have them, so encrypting the volume they are stored in makes the most sense to me. But having to repeatedly mount and unmount the volume makes me sad, because I don't like all the typing. Hence, this script.

Whenever I want to do some code signing, I down my network interfaces, and run this script, which mounts my code signing volume to ~/.gnupg. GnuPG sees the signing keys and knows what's up. This is important, because I don't want to mess around with GNUPGHOME or anything else if I can help it. Once I'm done with my code signing, I just re-run the script and re-enable my network interfaces. My signing keys are only accessible when there is no network connectivity, which is just how I want it.

To further reduce typing, create a ~/.gknoxrc file that contains the pathnames for the image file you want to mount and the mount point, like this:

# .gknoxrc
image=/path/to/image
mountpoint=/where/to/mount/it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment