#!/bin/zsh
#
# Tomb, the Crypto Undertaker
#
# a tool to easily operate file encryption of private and secret data
#
# Copyleft (C) 2007-2011 Denis Roio <jaromil@dyne.org>
#
# This source  code is free  software; you can redistribute  it and/or
# modify it under the terms of  the GNU Public License as published by
# the Free  Software Foundation; either  version 3 of the  License, or
# (at your option) any later version.
#
# This source code 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.
# Please refer to the GNU Public License for more details.
#
# You should have received a copy of the GNU Public License along with
# this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# startup wrapper to open tombs

TOMBEXEC="tomb"

if [ "$0" = "./tomb-open" ]; then
	TOMBEXEC="$PWD/tomb"
fi

# includes all shell functions in tomb
source $TOMBEXEC source

try() {
    which ${1} > /dev/null
    if [ $? = 0 ]; then 
	return 0
    else 
	return -1 
    fi
}

# popup notification
tomb-notify() {

    which notify-send > /dev/null
    if [ $? != 0 ]; then return 1; fi

    # look for our icon in common prefixes
    if   [ -r /usr/share/pixmaps/monmort.xpm ];       then icon=/usr/share/pixmaps/monmort.xpm
    elif [ -r /usr/share/icons/monmort.xpm ];         then icon=/usr/share/icons/monmort.xpm
    elif [ -r /usr/local/share/pixmaps/monmort.xpm ]; then icon=/usr/local/share/pixmaps/monmort.xpm
    elif [ -r /usr/local/share/icons/monmort.xpm ];   then icon=/usr/local/share/icons/monmort.xpm
    elif [ -r /opt/share/pixmaps/monmort.xpm ];       then icon=/opt/share/pixmaps/monmort.xpm
    elif [ -r /sw/share/pixmaps/monmort.xpm ];        then icon=/sw/share/pixmaps/monmort.xpm
    fi

    if [ -z $1 ]; then
	notify-send -i $icon \
	    -u low -h string:App:Tomb \
	    "Tomb version $VERSION" \
	    "Hi, I'm the Undertaker.
Let's start setting your Crypt?"
    else
	notify-send -i $icon ${@}
    fi
}


# USB plug auto detect using dmesg
# tested on ubuntu 10.04 and debian 6.0
# please test and patch on other systems if you can.
# TODO: use udev rules, see how archlinux folks document it:
# https://wiki.archlinux.org/index.php/System_Encryption_with_LUKS_for_dm-crypt
# here we could modularize the choice of methods using function pointers,
# so that they are configurable when calling tomb.
ask_usbkey() {
    unset usbkey_mount
    say "Waiting 1 minute for a usb key to connect"
    act -n "please insert your usb key "
    
    tomb-notify "Insert your USB KEY" \
	"Tomb is waiting 30 seconds for you to insert an external key."
    
    plugged=false
    c=0
    while [ "$plugged" != "true" ]; do
	dmesg | tail -n 12 | grep -q 'new.*USB device'
	if [ $? = 0 ]; then plugged=true; fi
	echo -n "."
	sleep .5
	c=`expr $c + 1`
	if [ $c -gt 60 ]; then
	    echo
	    die "timeout"
	fi
    done

    echo
    act -n "usb key inserted, attaching "
    
    c=0
    attached=false
    while [ "$attached" != "true" ]; do
        dmesg | tail -n 12| grep -q 'Attached.*removable disk'
        if [ $? = 0 ]; then attached=true; fi
        echo -n "."
        sleep  .5
        c=`expr $c + 1`
        if [ $c -gt 30 ]; then
            echo
            export usbkey_mount=none
            die "timeout"
        fi
    done

    echo
    act -n "usb attached, opening "
    
    # get the first partition
#    usbpart=`dmesg |tail -n 12 | grep '  sd.:' |cut -d: -f2 |tr -d ' '`
    for i in $(seq 1 10); do
        usbpart=$(dmesg | tail -n 12 | sed '/  sd.:/!d;s/^.*: \(sd.[0-9]*\)/\1/')
        if [ -n "$usbpart" ]; then
            break
        elif [ $i -eq 10 ]; then
            die "timeout" 1
        else
            echo -n .
            sleep 1
        fi
    done

    mtmp=`$TOMBEXEC mktemp tomb`
    sudo mount /dev/$usbpart $mtmp
    if [ $? = 0 ]; then
        usbmount=$mtmp
    else
        die "cannot mount usbkey partition $usbmount"
    fi

    echo
    act "usb key mounted on $usbmount"
    usbkey_mount=$usbmount
    return 0
}

launch_status() {
    # calculates the correct arguments to launch tomb-status tray
    # applet; it takes the tomb name as an argument and should be
    # launched after a successful tomb mount.
    if ! [ $1 ]; then
        die "cannot launch status tray applet: we don't even know the name of our tomb."
    fi

    if [ $DISPLAY ]; then
	tombname=${1}
    tombbase=`basename $tombname`
	tombmap=`mount -l | awk "/\[${tombbase}\]\$/"' { print $1 } '`
	tombmount=`mount -l | awk "/\[${tombbase}\]\$/"' { print $3 } '`
	if [ -x ./tomb-status ]; then # launch from build dir
	    ./tomb-status $tombmap $tombname $tombmount &!
	else
	    which tomb-status > /dev/null
	    if [ $? = 0 ]; then
		tomb-status $tombmap $tombname $tombmount &!
	    fi
	fi
    fi
}

# got an argument
if [ $1 ]; then # is it a file?

    tombdir=`dirname $1`
    tombfile=`basename $1`
    tombname=${tombfile%%\.*}

    if [ -f ${tombdir}/${tombfile} ]; then

	# is it a luks partition
	file ${tombdir}/${tombfile} | grep -i LUKS > /dev/null
	if [ $? = 0 ]; then # tomb is a valid LUKS file
        if [ -r ${tombdir}/${tombname}.tomb.key ]; then
            tombkey=${tombdir}/${tombname}.tomb.key
	    else
		ask_usbkey
        if ! [ $usbkey_mount ]; then # no usb key was mounted
            die "key not provided for tomb  $tombname: operation aborted" 1
        else # usb mounted, check key presence
            if [ -r ${usbkey_mount}/.tomb/${tombname}.tomb.key ]; then
                tombkey=${usbkey_mount}/.tomb/${tombname}.tomb.key
            elif [ -r ${usbkey_mount}/.tomb ]; then
                die "we can't find the right key, have a look yourself:\n$(ls -lha ${usbkey_mount}/.tomb)" 1
            else
                die "there are no keys stored in your usb" 1
            fi
        fi
	    fi
        if ! [ ${tombkey} ]; then # just to be sure
            die "key not found, operation aborted." 1
        else

            "${TOMBEXEC}" mount -k ${tombkey} ${tombdir}/${tombfile}
            success=$?
        fi

        if [ $usbkey_mount ]; then
            sudo umount ${usbkey_mount}
            rmdir  ${usbkey_mount}
            unset  usbkey_mount
        fi

        if [ $success = 0 ]; then	# mount was succesfull (with password and all)
            launch_status ${tombname}
            exit 0
        else
            tomb-notify "Tomb cannot open." "Are you knocking the wrong door?"
            exit 1
        fi
	else
	    tomb-notify "Not a real Tomb." "We found no real bones in there, or the tomb file permissions won't allow us in."
	    exit 1
	fi


    elif [ -d $1 ]; then # its a directory
	
# FIXME: somehow xdg-open loses mailcap mimes when executed by tomb-status
#   try xdg-open; if [ $? = 0 ]; then xdg-open ${1}; exit 0; fi
	try gnome-open; if [ $? = 0 ]; then gnome-open ${1}; exit 0; fi
	try thunar; if [ $? = 0 ]; then thunar ${1}; exit 0; fi
	try pcmanfm; if [ $? = 0 ]; then pcmanfm ${1}; exit 0; fi	
	try rox; if [ $? = 0 ]; then rox ${1}; exit 0; fi
	try fsviewer; if [ $? = 0 ]; then fsviewer ${1}; exit 0; fi
#	try xnc; if [ $? = 0 ]; then xnc ${1}; exit 0; fi
	tomb-notify "File manager not found." "Tomb cannot guess which filemanager you are using"
	exit 1
    fi
fi


# no argument but on graphical display: creation dialog
if [ "$1" != "wizard" ]; then
    if [ -z $DISPLAY ]; then
        no "tomb-open is a wrapper for the command 'tomb'"
        no "type 'tomb-open wizard' if you want to be guided"
        "${TOMBEXEC}" help
        exit 1
    fi
fi

# no arguments: start guided tomb creation
tomb-notify
# we do it on the desktop by default
if [ -r $HOME/Desktop ]; then 
    cd $HOME/Desktop;
# or inside HOME
else cd $HOME; fi
say "Tomb  -  simple commandline tool for encrypted storage"
say "version $VERSION ($DATE) by Jaromil @ dyne.org"
say "Guided creation of a new Tomb"
cat <<EOF

  A Tomb is  a special folder that keeps files  safe using a password:
  it makes use  of strong encryption and helps you keep  the keys on a
  separate USB storage for safer transports.

  Inside a Tomb  you can store private informations  without fear that
  other people  possessing it will discover your  secrets, unless they
  have your USB key and your password.

  If you choose  to proceed now, we'll guide  you through the creation
  of a new Tomb.

  If you will, I'll be your Crypto Undertaker.

  Do you want to proceed, Master? (y/n)
EOF
echo -n "> "
read -q
if [ "$?" != 0 ]; then
    die "Operation aborted" 1
fi
    # let's proceed
say "Please type in the name for your new tomb file:"
echo -n "> "
read -u 1 tombname
say "How big you want the Tomb to be?"
act "Type a size number in Megabytes:"
echo -n "> "
read -u 1 tombsize
if [[ "$tombsize" != <-> ]]; then
    die "Only digit allowed! Operation aborted"
fi
clear
say "You have commanded the creation of this Tomb:"
act "$tombname ( $tombsize MBytes )";
echo
cat <<EOF
  Please confirm if you want to proceed now:

  You will  need the super-user  (sudo) password for the  computer you
  are using, as well time available.

  Depending how big  your tomb will be, make sure  you are not running
  low on batteries.

  If  you are  remotely connected  to  a server,  make sure  to use  a
  detachable screen.

  Considering 1GB takes usually little less than an hour to be digged.

EOF
say "  Digging will take quite some time! Should we start? (y/n)"
echo -n "> "
read -q
if [ $? != 0 ]; then
    die "Operation aborted." 1

fi
cat <<EOF
  Operation confirmed!  we will now call the undertaker to do its job,
  but in order to do so you will need to provide your sudo password:
EOF

tombfile=${tombname}.tomb
"${TOMBEXEC}" create --ignore-swap -s $tombsize ${tombfile}

if [ $? != 0 ]; then
    die "An error occurred creating tomb, operation aborted."
fi

tomb-notify "The Tomb is ready!" "We will now open your new Tomb for the first time."
cat <<EOF
  Would you like to save the key on  an external usb device?

  This is recommended for safety:
  Always keep the key in a different place than the door!

  If you answer yes, you'll need a USB KEY now: (y/n)
EOF
# tomb-notify "Tomb has forged a key." "Would you like to save it on USB?" 
echo -n " >  "
read -q
if [ $? = 0 ]; then
    ask_usbkey
    if [  ${usbkey_mount} ]; then

	sudo mkdir -m 0700 -p ${usbkey_mount}/.tomb
	sudo cp -v ${tombfile}.key ${usbkey_mount}/.tomb/
	sudo chmod -R go-rwx ${usbkey_mount}/.tomb

	yes "${tombname}.key succesfully saved on your USB"
	act "now we'll proceed opening your brand new tomb"

	"${TOMBEXEC}" open -k ${tombfile}.key ${tombfile}
	if [ $? = 0 ]; then
	    launch_status ${tombname}
	fi

	rm -f ${tombfile}.key

	sudo umount ${usbkey_mount}
	rmdir  ${usbkey_mount}
	unset usbkey_mount

	exit 0
    fi
fi

cat <<EOF
  Impossible to save the key on USB.

  We recommend to preserve the key  in a separate place!  You can move
  it yourself later, place it in a hidden directory named .tomb inside
  the first partition of an usb key.

EOF

"${TOMBEXEC}" open -k ${tombname}.tomb.key ${tombfile}
if [ $? = 0 ]; then
    launch_status ${tombname}
fi

exit 0
