#!/bin/sh

. /usr/share/debconf/confmodule

db_capb "backup"

if [ "$1" ]; then
    ROOT="$1"
else
    ROOT=
fi
export ROOT

unset_db() {
    db_set cryptpasswd/device ""
    db_set cryptpasswd/crypt-password ""
    db_set cryptpasswd/crypt-password-again ""
}

check_crypt_password() {
    s="${1}"

    if [ ${#s} -lt 8 ]; then
        return 1
    else
        return 0
    fi
}

find_crypt_root() {
    rootmnt=$(findmnt -fn -o SOURCE /)
    dmlink=$(readlink ${rootmnt})
    physroot=""

    if [ $? -ne 0 ]; then
        return 1
    else
        if [ -z ${dmlink} ]; then
            return 1
        else
            dmbase=$(basename $dmlink)

            for DEV in $(ls /sys/class/block/); do
                if [ -e /sys/class/block/${DEV}/holders/${dmbase} ]; then
                    physroot="/dev/${DEV}"
                fi
            done
        fi
    fi

    if [ -z ${physroot} ]; then
        return 1
    else
        echo "${physroot}"
    fi

    return 0
}

# Create the template file
cat > /tmp/nvcryptpasswd.template << EOF

Template: cryptpasswd/title
Type: title
Description: Set root partition passphrase

Template: cryptpasswd/device
Type: string
Description: The crypt device
 Device that we are setting the passphrase on.

Template: cryptpasswd/crypt-password
Type: password
Description: Choose a root partition passphrase:
 The minimum length of the passphrase must be 8 characters. A good passphrase
 will contain a mixture of letters, numbers and punctuation  and should be
 changed at regular intervals.

Template: cryptpasswd/crypt-password-again
Type: password
Description: Re-enter root partition passphrase to verify:
 Please enter the same passphrase again to verify you have typed it
 correctly.

Template: cryptpasswd/crypt-password-mismatch
Type: error
Description: Passphrase input error
 The two passphrases you entered were not the same. Please try again.

Template: cryptpasswd/crypt-password-criteria
Type: error
Description: Passphrase does not meet criteria.
 The passphrase should be 8 characters or longer.

EOF

# Load your template
db_x_loadtemplatefile /tmp/nvcryptpasswd.template cryptpasswd

# Set title for your custom dialog box
db_settitle cryptpasswd/title

db_set cryptpasswd/device ""
db_set cryptpasswd/crypt-password ""
db_set cryptpasswd/crypt-password-again ""
db_fset cryptpasswd/crypt-password seen false
db_fset cryptpasswd/crypt-password-again seen false

# Allow users to load templates without proceeding to state-machine
if [ "$1" = "load_only" ]; then
    echo "Loading templates only, exiting now."
    exit 0
fi

# Bail out here if there is no crypt
phys_crypt=$(find_crypt_root)
if [ $? -ne 0 ]; then
    unset_db
    exit 0
else
    db_set cryptpasswd/device "${phys_crypt}"
fi

# Exit if the device doesn't have a LUKS header
cryptsetup luksDump ${phys_crypt} > /dev/null 2>&1
if [ $? -ne 0 ]; then
    unset_db
    exit 0
fi

# Exit if default password is not in use in slot 0
DEFPASSWD="nvidia3d"
DEFSLOT="0"
printf "${DEFPASSWD}" | cryptsetup luksOpen --test-passphrase --key-slot ${DEFSLOT} ${phys_crypt}
if [ $? -ne 0 ]; then
    echo "Default password not in use"
    unset_db
    exit 0
fi

# Main loop starts here. Use a state machine to allow jumping back to
# previous questions.
STATE=0
while :; do
    case "$STATE" in
        0)
            # below three stesp are fundamental to wotk with debconf
            #
            # 1. prepare qustion
            db_input critical cryptpasswd/crypt-password || true
            # 2. Tell db to prompt a question for the user
            db_go || true
            # 3. collect the input from user
            db_get cryptpasswd/crypt-password

            USER_PW="$RET"
            if [ "$USER_PW" ] && check_crypt_password "$USER_PW"; then
                db_input critical cryptpasswd/crypt-password-again || true
                db_go || true
                db_get cryptpasswd/crypt-password-again
                if [ "$USER_PW" != "$RET" ]; then
                    db_set cryptpasswd/crypt-password ""
                    db_set cryptpasswd/crypt-password-again ""
                    db_fset cryptpasswd/crypt-password-mismatch seen false
                    db_input critical cryptpasswd/crypt-password-mismatch
                    db_fset cryptpasswd/crypt-password seen false
                    db_fset cryptpasswd/crypt-password-again seen false
                    STATE=0
                    continue
                fi
            else
                db_set cryptpasswd/crypt-password ""
                db_input critical cryptpasswd/crypt-password-criteria
                db_fset cryptpasswd/crypt-password seen false
                STATE=0
                continue
            fi
            ;;
        *)
            break
            ;;
    esac

    if db_go; then
        STATE=$(($STATE + 1))
    else
        STATE=$(($STATE - 1))
    fi
done

if [ "$STATE" = -1 ]; then
    exit 1
fi

exit 0
