summaryrefslogtreecommitdiff
path: root/gpgsecure.sh
blob: 261d0469c754bf2fc84c4893240548c28e1fcdf7 (plain)
    1 #!/usr/bin/env bash
    2 # GPGSecure is a shell script that manages GPG encrypted archives
    3 # Copyright (C) 2018  Aaron Ball <nullspoon@oper.io>
    4 #
    5 # This program is free software: you can redistribute it and/or modify
    6 # it under the terms of the GNU General Public License as published by
    7 # the Free Software Foundation, either version 3 of the License, or
    8 # (at your option) any later version.
    9 #
   10 # This program is distributed in the hope that it will be useful,
   11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 # GNU General Public License for more details.
   14 #
   15 # You should have received a copy of the GNU General Public License
   16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
   17 
   18 
   19 export KEY=${KEY:-} # GPG key to encrypt the container with
   20 export DIR          # Directory path to present the gpg archive to
   21 export TMP          # Temp directory in memory to decrypt to
   22 
   23 trap shutdown SIGINT SIGTERM SIGKILL SIGQUIT SIGHUP
   24 
   25 
   26 shutdown() {
   27   tar -C "${TMP}" -c . | gpg -e --recipient "${KEY}" > "${DIR}.tar.gpg"
   28   # Shred all files in memory
   29   find "${TMP}" -type f -exec shred -n 100 -f -u "{}" \;
   30   # Delete the link
   31   rm "${DIR}"
   32   # Delete the temp dir from memory
   33   rm -rf "${TMP}"
   34   sync
   35   exit
   36 }
   37 
   38 
   39 writeback() {
   40   trap shutdown SIGINT SIGTERM SIGKILL SIGQUIT SIGHUP
   41   # Sync back to disk every 10 seconds
   42   while [ 0 ]; do
   43     #printf '%s   Syncing back to encrypted storage\n' "$(date '+%F %T')"
   44     tar -C "${TMP}" -c . | gpg -e --recipient "${KEY}" > "${DIR}.tar.gpg"
   45     if [ $? -gt 0 ]; then
   46       printf 'WARNING: Something went wrong syncing back to encrypted storage\n'
   47       printf 'Your data is likely in danger.\n'
   48       printf 'If you see this message more than once, take a manual backup\n'
   49     fi
   50     sleep 20 &
   51     wait $!
   52   done
   53 }
   54 
   55 
   56 open() {
   57   local archive="${1}"
   58 
   59   # Convert DIR to absolute path to avoid cd issues
   60   local dirname="$(cd $(dirname ${archive}) && pwd)"
   61   local basename="$(basename ${archive})"
   62   local dir="${dirname}/${basename}"
   63   # Create a temp dir in memory to extract to for safety
   64   export TMP=$(mktemp -d /tmp/dec-XXXXXXXXXXXXXX)
   65   # Link!
   66   ln -s "${TMP}" "${dir}"
   67   
   68   if [ ! -f "${dir}.tar.gpg" ]; then
   69     # Tell the user if that encrypted archive does not exist.
   70     printf 'Encrypted archive does not exist. Creating.\n'
   71   else
   72     # Extract the encrypted tarchive if it exists
   73     gpg -d "${dir}.tar.gpg" | tar -C "${TMP}" -x
   74   fi
   75 
   76   writeback &
   77   echo $! > "${dirname}/.${basename}.pid"
   78 }
   79 
   80 
   81 status() {
   82   local archive=${1}
   83 
   84   local dirname="$(dirname ${archive})"
   85   local basename="$(basename ${archive})"
   86   local pidfile="${dirname}/.${basename}.pid"
   87 
   88   # If no pidfile, assume closed
   89   if [ ! -f "${pidfile}" ]; then
   90     printf '%s is closed\n' "${archive}"
   91     return 0
   92   fi
   93 
   94   local pid="$(cat ${pidfile})"
   95 
   96   ps "${pid}" 2>/dev/null 1>/dev/null
   97   if [ $? -eq 0 ]; then
   98     printf '%s is open\n' "${archive}"
   99   elif [ $? -gt 0 ]; then
  100     printf '%s is closed but a stale pidfile was found. Removing\n' "${archive}"
  101     rm -f "${pidfile}"
  102   else
  103     printf '%s is closed\n' "${archive}"
  104   fi
  105 }
  106 
  107 
  108 close() {
  109   local archive=${1}
  110 
  111   local dirname="$(dirname ${archive})"
  112   local basename="$(basename ${archive})"
  113   local pidfile="${dirname}/.${basename}.pid"
  114   local pid="$(cat ${pidfile})"
  115 
  116   ps "${pid}" 2>/dev/null 1>/dev/null
  117   if [ $? -gt 0 ]; then
  118     printf "Stale pidfile detected but share is not open. Removing\n"
  119     rm -f "${pidfile}"
  120     return 1
  121   else
  122     # Send SIGTERM (15) to tell the process to exit cleanly
  123     kill -15 "${pid}"
  124     [ $? -eq 0 ] && rm "${pidfile}" && return 0
  125 
  126     printf 'Error closing archive "%s"\n' "${archive}"
  127     return 1
  128   fi
  129 }
  130 
  131 
  132 main() {
  133   local action="${1}"
  134   local archive="${2}"
  135 
  136   # Input validation
  137   if [ -z "${action:-}" ]; then
  138     printf 'Action (open, close, or status) required\n'
  139     return 1
  140   fi
  141   if [ -z "${archive:-}" ]; then
  142     printf 'Archive to decrypt required\n'
  143     return 1
  144   fi
  145 
  146   if [ -z "${KEY}" ]; then
  147     printf 'KEY variable unset. Cannot re-encrypt. Exiting.\n'
  148     return 1
  149   fi
  150 
  151   gpg --list-keys ${KEY} 2>/dev/null 1>/dev/null
  152   if [ $? -gt 0 ]; then
  153     printf 'Unknown key "%s". Cannot proceed.\n' "${KEY}"
  154     return 1
  155   fi
  156 
  157   local dirname="$(dirname ${archive})"
  158   local basename="$(basename ${archive})"
  159   export DIR="${dirname}/${basename}"
  160 
  161   if [ "${action}" = 'open' ]; then
  162     # Check if already open
  163     if [ -f "${dirname}/.${basename}.pid" ]; then
  164       printf 'ERROR: Archive "%s" is already open\n' "${archive}"
  165       return 1
  166     else
  167       printf 'Opening!\n'
  168       open "${archive}"
  169       return $?
  170     fi
  171   elif [ "${action}" = 'close' ]; then
  172     # Check if already closed
  173     if [ ! -f "${dirname}/.${basename}.pid" ]; then
  174       printf 'ERROR: Archive "%s" is not open\n' "${archive}"
  175       exit 1
  176     else
  177       printf 'Closing!\n'
  178       close "${archive}"
  179       return $?
  180     fi
  181   elif [ "${action}" = 'status' ]; then
  182     status "${archive}"
  183     return $?
  184   fi
  185 
  186   # If we make it here, something went wrong.
  187   printf 'ERROR: Unknown action "%s"\n' "${action}"
  188   return 1
  189 }
  190 
  191 main ${@}

Generated by cgit