#!/bin/bash
# -----------------------------------------------------------------------------
# zzzendec -- encrypt/decrypt a file,
#             optionally "securely" delete it after encryption
# Copyright (C) 2003 Fabian "zzznowman" Pietsch <fabian@zzznowman.dyndns.org>
#
# Distributed under the GNU GPL (General Public Licence)
# zzzendec is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# zzzendec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# -----------------------------------------------------------------------------
# Version 0.1 (2003-10-13)
# TODO:  o fix directory handling - they're correctly encrypted and decrypted atm,
#          but deletion won't work right; also some success checks will fail

# (see further below for configuration variables -- function section
#    had to be moved in front of them)


# === function declarations ===

# functions used internally:
#   info, warn	output functions
#   fail	exit on error; optionally call usage
#   usage 	display usage information
#   wipe	delete file (-f: without confirmation) by either rm or zzzwipe
zedfail() {
    [ -n "$*" ] && if [ "$1" == "usage" ]; then
        zedusage 1>&2
    else
        zedwarn "$@"
    fi
    exit 1
}

zedinfo() {
    echo "$BASENAME: $*"
}

zedusage() {
    echo -e "\
$BASENAME: usage: $0 [-hs] [-r RECIPIENT] -ed FILE\n\
zzzendec $ZEDVERSION -- encrypt/decrypt a file preserving its time stamp
-e\tencrypt FILE using GnuPG\n\
-d\tdecrypt FILE using GnuPG\n\
-h\tdisplay this usage information\n\
-p\tset permissions to go-rwx before encryption or after decryption\n\
-r\tset recipient (for GnuPG encryption)\n\
-s\tsecurely delete FILE after encryption (using zzzwipe)"
}

zedwarn() {
    echo "$BASENAME: $*" 1>&2
}

zedwipe() {
    local ZEDWIPEFORCE="0"
    [ "$1" == "-f" ] && {
        ZEDWIPEFORCE="1"
        shift
    }

    # check requested operation for validity
    [ "$#" -eq 1 ] || {
        zedwarn "zedwipe(): invalid call: $*"
        return 1
    }
    { [ -f "$1" ] || [ "$ZEDWIPEFORCE" -eq 0 -a -d "$1" ]; } || {
        [ -d "$1" ] \
          && zedwarn "zedwipe(): $1: directory, but -f specified" \
          || zedwarn "zedwipe(): $1: no such file or directory"
        return 1
    }

    # wipe (or at least delete) the file
    case "$ZEDWIPEFORCE" in
    1)  "${ZEDCMDWIPE:-rm}" -f "$1";;
    *)  "${ZEDCMDWIPE:-rm}" -i "$1";;
    esac
}


# === configuration variables ===
BASENAME="`basename "$0"`"
ZEDVERSION="0.1 (2003-10-12)"
ZEDCMDGPG="`type -p gpg`" || zedfail "ERROR: gpg not found"
ZEDCMDTAR="`type -p tar`" || zedfail "ERROR: tar not found"
ZEDCMDWIPE="`type -p zzzwipe`"
ZEDMODE=""
ZEDFILE=""
ZEDRECIPIENT="=Fabian Pietsch <fabian@zzznowman.dyndns.org>"
ZEDDEL="0"
ZEDPERM="0"


# === command line processing ===

# process command line arguments
while getopts "hpsr:e:d:" ZEDOPT; do
    case "$ZEDOPT" in
    h)  zedusage; exit 0;;
    e)  ZEDMODE="e"; ZEDFILE="$OPTARG";;
    d)  ZEDMODE="d"; ZEDFILE="$OPTARG";;
    p)  ZEDPERM="1";;
    r)  ZEDRECIPIENT="$OPTARG";;
    s)  ZEDDEL="1";;
    *)  zedfail usage;;
    esac
done

# any command line arguments left?
[ "$#" -ge "$OPTIND" ] && {
    zedwarn "trailing command line arguments"
    zedfail usage
}

# check desired operation for validity
[ -z "$ZEDMODE" ] && {
    zedwarn "no -e or -d given"
    zedfail usage
}
[ -z "$ZEDFILE" ] && {
    zedwarn "no file given"
    zedfail usage
}
# remove trailing /, as it might be a directory -- do so before any other testing
ZEDFILE="${ZEDFILE%/}"
[ -f "$ZEDFILE" -o -d "$ZEDFILE" ] \
  || zedfail "$ZEDFILE: no such file or directory"
if [ -n "$ZEDDEL" ] && [ "$ZEDDEL" -ne 0 ]; then
    [ -n "$ZEDCMDWIPE" ] \
      || zedfail "file deletion requested, but wipe command not found"
    zedwarn "WARNING: (\"secure\") FILE DELETION TURNED ON"
else
    ZEDDEL="0"
fi


# === real operation starts here ===

case "$ZEDMODE" in
e)  # encrypt
    ZEDTARFILE="$ZEDFILE.tar"
    [ -f "$ZEDTARFILE" ] \
      && zedfail "$ZEDTARFILE: temporary file already exists"
    ZEDDESTFILE="$ZEDTARFILE.gpg"
    #[ -f "$ZEDDESTFILE" ] && {
    #    zedwarn "$ZEDDESTFILE: destination file already exists"
    #    zedfail
    #}
    zedinfo "encrypting $ZEDFILE for \"$ZEDRECIPIENT\"..."

    # set permissions?
    [ "$ZEDPERM" -ne 0 ] && chmod -cR go-rwx "$ZEDFILE"

    # first tar the file
    #   (to preserve modification times and allow encryption of directories)
    "$ZEDCMDTAR" -cf "$ZEDTARFILE" "$ZEDFILE" \
      || zedfail "ERROR: tar exited $? -- aborting"

    # encrypt temporary tar archive using gpg
    "$ZEDCMDGPG" -fr "$ZEDRECIPIENT" "$ZEDTARFILE" || {
        zedwarn "ERROR: gpg exited $? -- aborting"
        zedwipe -f "$ZEDTARFILE"
        zedfail
    }

    # remove temporary tar archive
    zedwipe -f "$ZEDTARFILE"

    # encrypted file really there?
    [ -f "$ZEDDESTFILE" ] \
      || zedfail "ERROR: expected gpg to create $ZEDDESTFILE, but it didn't"

    # set permissions?
    [ "$ZEDPERM" -ne 0 ] && chmod -cR go-rwx "$ZEDDESTFILE"

    # delete cleartext file?
    if [ "$ZEDDEL" -ne 0 ]; then
        zedinfo "deleting cleartext file $ZEDFILE..."
        zedwipe "$ZEDFILE"
    #else
    #    zedwarn "WARNING: cleartext file $ZEDFILE is still there"
    fi
    [ -f "$ZEDFILE" ] \
      && zedwarn "WARNING: cleartext file $ZEDFILE is still there"

    zedinfo "successfully encrypted $ZEDFILE to $ZEDDESTFILE."
    ;;
d)  # decrypt
    echo "$ZEDFILE" | grep -q '\.gpg$' \
      || zedfail "$ZEDFILE: no .gpg file"
    ZEDTARFILE="`echo "$ZEDFILE" | sed 's/\.gpg$//'`"
    echo "$ZEDTARFILE" | grep -q '\.tar$' \
      || zedfail "$ZEDFILE: file name suggests there's no .tar archive contained"
    [ -f "$ZEDTARFILE" ] \
      && zedfail "$ZEDTARFILE: temporary file already exists"
    ZEDDESTFILE="`echo "$ZEDTARFILE" | sed 's/\.tar$//'`"
    [ -f "$ZEDDESTFILE" ] \
      && zedfail "$ZEDDESTFILE: destination file already exists"
    zedinfo "decrypting $ZEDFILE..."

    # decrypt temporary tar archive using gpg
    "$ZEDCMDGPG" --decrypt-files "$ZEDFILE" \
      || zedfail "ERROR: gpg exited $? -- aborting"

    # is tar archive really there now?
    [ -f "$ZEDTARFILE" ] \
      || zedfail "ERROR: expected gpg to create $ZEDTARFILE, but it didn't"

    # extract temporary tar archive
    "$ZEDCMDTAR" -xvf "$ZEDTARFILE" \
      || zedfail "ERROR: tar exited $? -- aborting"

    # remove temporary tar archive
    zedwipe -f "$ZEDTARFILE"

    # destination file really there?
    [ -f "$ZEDDESTFILE" ] \
      || zedfail "ERROR: $ZEDDESTFILE: destination file wasn't created"

    # set permissions?
    [ "$ZEDPERM" -ne 0 ] && chmod -cR go-rwx "$ZEDDESTFILE"

    zedinfo "successfully decrypted $ZEDFILE to $ZEDDESTFILE."
    ;;
*)  # huh?
    zedwarn "internal error -- please make a bug report"
    zedwarn "(no files have been modified)"
    zedfail
    ;;
esac

