summaryrefslogtreecommitdiff
path: root/pt
blob: dc4b50a12cc9f9072b600ab79d15508e071c4c37 (plain)
    1 #!/usr/bin/env bash
    2 #
    3 # Automatically types the username and password from the pass entry specified
    4 # as argument one. The required password-store backend is pass, the standard
    5 # unix password manager.
    6 #
    7 # A simple workflow for this may be to go to a website requiring a username and
    8 # password. Select the username field, open a program launcher such as rofi or
    9 # dmenu, then execute 'quicktype password-name'.
   10 #
   11 # Note that for this to work, each pass entry must match the following criteria
   12 # * The password is on the first line (this is the pass standard)
   13 # * The username can be anywhere in the file, but the line must look like
   14 #   'username: <password>'
   15 # 
   16 # Depends on: pass xdotool
   17 #
   18 
   19 
   20 export PASSWORD_STORE_DIR=~/.password-store
   21 
   22 
   23 #
   24 # Writes log output to terminal and notification daemon, if one is present.
   25 #
   26 function log {
   27   local msg="${@}"
   28 
   29   if [[ $(type -p notify-send) != '' ]]; then
   30     notify-send "$(basename ${0}):" "${msg}"
   31   fi
   32   printf -- '%s\n' "${msg}"
   33 }
   34 
   35 
   36 #
   37 # Ensures required tools are available, returning code 1 and log if any of them
   38 # are not.
   39 #
   40 function check_env {
   41   # Verify pass is installed and in the PATH.
   42   if [[ $(type -p pass) == '' ]]; then
   43     log "Error: Could not find pass." && return 1
   44   fi
   45 
   46   # Verify xdotool is installed and in the path
   47   if [[ $(type -p xdotool) ==  '' ]]; then
   48     log "Error: Could not find xdotool." && return 1
   49   fi
   50 
   51   # Verify /dev/null is a character device, on the off chance someone with root
   52   # access is trying to capture output redirected there.
   53   local devstat=$(ls -l /dev/null)
   54   if [[ ${devstat:0:1} != 'c' ]]; then
   55     log "Error: /dev/null is not a character device."
   56     return 1
   57   fi
   58 
   59   return 0
   60 }
   61 
   62 
   63 #
   64 # Gets a field's value from the specified [multiline] string, using the
   65 # specified delimiter.
   66 #
   67 # @param content Content to extract field value from
   68 # @param delim   Delimiter seperating fields and values
   69 # @param field   Field name to get value for
   70 #
   71 getfield() {
   72   local _content="${1:-}"
   73   local _delim="${2:-}"
   74   local _field="${3:-}"
   75 
   76   printf -- "%s" "${_content}" \
   77     | sed -n "s/${_field}${_delim} *\(.*\)/\1/p" \
   78     | head -n 1
   79 }
   80 
   81 
   82 typefields() {
   83   local _user="${1:-}"
   84   local _pass="${2:-}"
   85   local _delim="${3:-}"
   86 
   87   # Type the password
   88   xdotool type --delay 15 "${_user}"
   89   xdotool key "${_delim}"
   90   xdotool type --delay 15 "${_pass}"
   91 }
   92 
   93 
   94 pastefields() {
   95   local _user="${1:-}"
   96   local _pass="${2:-}"
   97   local _delim="${3:-}"
   98 
   99   # Save clipboard first
  100   local _origclipboard="$(xclip -o -selection clipboard)"
  101 
  102   # Sleep .2 for those apps that read only "key up" events without first reading
  103   # "key down", causing it to read pressing enter to execute pt as submitting
  104   # the form (bad js devs, bad!).
  105   sleep .2
  106   # Save username to clipboard and paste
  107   printf -- "%s\n" "${_user}" | xclip -selection clipboard
  108   xdotool key "Control+v" "${_delim}"
  109 
  110   # Save password to clipboard and paste
  111   printf -- "%s\n" "${_pass}" | xclip -selection clipboard
  112   xdotool key "Control+v"
  113 
  114   # Restore original clipboard value
  115   printf -- "%s\n" "${_origclipboard}" | xclip -selection clipboard
  116 }
  117 
  118 
  119 function main {
  120   local _passentry    # Contents of the requested pass entry
  121   local _passpassword # Password from the pass entry
  122   local _passusername # Username field from the pass entry
  123   local _passdelim    # UI Field delimiter (Tab, Return), from the pass entry
  124   local _passsubmit   # Boolean submit (1,y,yes...), from the pass entry
  125   local _passtype     # Boolean type (1,y,yes...), from the pass entry
  126 
  127   local _delim=Tab    # Default delimiter if not specified in pass entry
  128   local _submit=0     # Default submit value if not specified in pass entry
  129   local _type=0       # Whether or not to type or paste (type=0 will paste)
  130 
  131   # Exit failure if no password was specified
  132   [[ -z ${1} ]] && log "Please specify a password to be typed" && exit 1
  133 
  134   check_env || exit 0
  135   
  136   # Check if the password exists in the store
  137   # Also, copy the contents into a variable if it exists
  138   _passentry="$(pass ${@} 2>/dev/null)"
  139   [[ $? -gt 0 ]] && log "Error: '${@}' is not in the password store" && exit 1
  140   
  141   # Parse pass output into appropriate variables 
  142   _passpassword=$(printf -- "%s" "${_passentry}" | head -n1 | sed 's/`/\`/g')
  143   _passusername=$(getfield "${_passentry}" ':' 'username')
  144   _passdelim=$(getfield    "${_passentry}" ':' 'delim')
  145   _passsubmit=$(getfield   "${_passentry}" ':' 'submit')
  146   _passtype=$(getfield     "${_passentry}" ':' 'type')
  147 
  148   # If any of the known 'submit' values are specified, set submit to 1
  149   if [ "${_passsubmit}" = '1' ] \
  150     || [ "${_passsubmit}" = 'y' ] \
  151     || [ "${_passsubmit}" = 'yes' ] \
  152     || [ "${_passsubmit}" = 'true' ]; then
  153     _submit=1
  154   fi
  155 
  156   # If any of the known 'type' values are specified, set type to 1
  157   if [ "${_passtype}" = '1' ] \
  158     || [ "${_passtype}" = 'y' ] \
  159     || [ "${_passtype}" = 'yes' ] \
  160     || [ "${_passtype}" = 'true' ]; then
  161     _type=1
  162   fi
  163 
  164   # Type username/password if type == 1, otherwise paste username/password
  165   if [ "${_type}" = '1' ]; then
  166     typefields "${_passusername}" "${_passpassword}" "${_delim}"
  167   else
  168     pastefields "${_passusername}" "${_passpassword}" "${_delim}"
  169   fi
  170   
  171   [ "${_submit}" = 1 ] && xdotool key Return
  172 }
  173 
  174 main ${@}

Generated by cgit