#!/bin/sh # Fills a password for a given website # original script by Avalon Williams (avalonwilliams@protonmail.com) # This version uses the window id to know the url of the surf window # and to know which fifo it must use. Then it injects javascript code. # that will fill the forms with the credentials printf '\n\n' # dependencies: # - surf fifo patch (http://surf.suckless.org/patches/fifo/) # - xprop # - 'pass' with password store in form dir/url/pass.gpg # $1: winid fifodir="$HOME/.config/surf/fifo" if [ -z "${winid:=$1}" ]; then winid="$(osurfls | dmenu -c -F -i | cut -f1 -d' ')" fi [ "$winid" ] || exit 1 fifo="$fifodir/$winid" [ -p "$fifo" ] || exit 2 # Get only domain name + top-level domain url="$(xprop -id "$winid" _SURF_URI | cut -f 2 -d'"' | sed 's,^.*://\([^/]*\)/.*,\1,' | sed -r -e 's/^([^.]+)\.([^.]+)\.([^.]+)$/\2.\3/')" [ "$url" ] || exit 3 printf >&2 'url: %s\n' "$url" # get pass with url and ask if multiple are found pass="$({ find $PASSWORD_STORE_DIR/websites/ -type f -name '*.gpg' | grep "$url/" || echo; } | head -n 1 | sed "s,$PASSWORD_STORE_DIR/,,;s/\.gpg$//" | dmenu -c)" # if dmenu was stopped, exit [ $? -gt 0 ] && exit 4 # if no password was found, search through password store manually with dmenu if [ -z "$pass" ]; then store="${PASSWORD_STORE_DIR:-$HOME/.password-store}" while [ -d "$store/$file" ]; do choice="$(find "$store/$file" \ -maxdepth 1 -mindepth 1 \ -not -name '.*' -type d -printf "%y\t%f\n" -o \ -not -name '.*' -not -type d -printf "%y\t%f\n" | sort -k1 -k2 | cut -f 2 | sed 's/\.gpg$//' | dmenu -c)" [ "$choice" ] || exit 1 [ -z "$file" ] && file="$choice" || file="$file/$choice" done pass="$file" fi printf >&2 'pass: %s\n' "$pass" herbe "filling ${pass#websites/}" & # Get password and username in variables with only one call to 'pass' # escape single quotes eval "$(pass show "$pass" | sed -n "1s/'/'\\\\''/g;1s/.*/password='&'/p;s/^login: \?\(.\+\)/username='\1'/p")" printf '%s : %s\n' "$username" "$password" # Escape quotes and backslashes for javascript javascript_escape() { # The string will be inside double quotes # we need to add 2 backslashes, one for shell (heredoc) and one for javascript printf '%s' "$1" | sed -s 's,["\\],\\\\&,g' } js() { cat < 0 && elem.offsetHeight > 0; }; function hasPasswordField(form) { var inputs = form.getElementsByTagName("input"); for (var j = 0; j < inputs.length; j++) { var input = inputs[j]; if (input.type == "password" || input.autocomplete == "password" || input.name == "password") { return true; } } return false; }; function loadData2Form (form) { var inputs = form.getElementsByTagName("input"); for (var j = 0; j < inputs.length; j++) { var input = inputs[j]; if (isVisible(input) && (input.type == "text" || input.type == "email")) { input.focus(); input.value = "$(javascript_escape "$username")"; input.blur(); } if (input.type == "password" || input.name == "password" || input.autocomplete == "password" || input.id == "password" ) { input.focus(); input.value = "$(javascript_escape "$password")"; input.blur(); } } }; var forms = document.getElementsByTagName("form"); for (i = 0; i < forms.length; i++) { if (hasPasswordField(forms[i])) { loadData2Form(forms[i]); // forms[i].submit(); } } EOF } printjs() { js | sed 's,//.*$,,' | tr '\n' ' ' } echo "inject $(printjs)" >>"$fifo"