├── importpwd.sh ├── README.org └── pwd.sh /importpwd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ksh 2 | # (c) 2013 s@ctrlc.hu 3 | # 4 | # This is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation; either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # warning! i accidentally clobbered the original version of this. this 10 | # is mostly a quick rewrite from memory. please test this before using 11 | # it live. 12 | 13 | # use the firefox password-export addon to feed this script. 14 | # invoke with 15 | # cat password-export | fgrep '$data/$hosthash/$userhash 38 | done 39 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * pwd.sh 2 | a simple password manager for X11. 3 | 4 | All passwords are stored encrypted using a gpg public key, this means 5 | you can even use your cryptostick or equivalent to protect your 6 | passwords in storage. 7 | 8 | * Install 9 | depends: 10 | #+BEGIN_SRC sh 11 | apt-get install gnupg xdotool xclip suckless-tools ssh-askpass apg 12 | #+END_SRC 13 | (suckless-tools provides dmenu) 14 | 15 | configure pwd.sh 16 | #+BEGIN_SRC sh 17 | mkdir ~/.pwd 18 | cat >~/.pwd/.cfg < 20 | salt="rainbow-stainer" # this should be some random string 21 | EOT 22 | #+END_SRC 23 | ** Setup in your window manager 24 | Bind the following to some window manager keys 25 | #+BEGIN_SRC sh 26 | pwd.sh # for getting a password 27 | pwd.sh a # creating a new random password 28 | #+END_SRC 29 | pwd.sh accepts an optional *1st* parameter (preceding the 'a') for 30 | specifying an alternative root for the password storage. 31 | * Adding passwords 32 | A new password is automatically generated, the URL or window title 33 | used for indexing, and only the username is queried using kdialog. 34 | * Getting passwords 35 | pwd.sh uses X11 window titles or in case of firefox, uzbl, luakit, 36 | chromium, vimperator, pentadactyl and iceweasel the current page url 37 | for indexing users and keys. The title or url is hashed with a salt 38 | for their final directory name. Users are stored in separate files, 39 | similarly using hashed names underneath their respective "site" 40 | directory. Check out ~/.pwd after issuing a few "pwd.sh a" 41 | invocations. 42 | * Import from firefox 43 | importpwd.sh imports passwords from the firefox password exporter addon. 44 | #+BEGIN_SRC sh 45 | cat password-export | fgrep '' 50 | } 51 | 52 | function xdoget { 53 | title="$1" 54 | shift 1 55 | echo -n '' | /usr/bin/xclip -i 56 | sleep 0.2 57 | /usr/bin/xdotool key --window $windowid $* 58 | retries=0 59 | while [[ retries -lt 3 ]]; do 60 | sleep 0.2 61 | x=$(/usr/bin/xclip -o) 62 | [[ "$x" =~ ^https?:.* ]] && { 63 | echo $x | cut -d'/' -f1-3 64 | break 65 | } 66 | retries=$((retries+1)) 67 | done 68 | [[ $retries -ge 3 ]] && echo "$title" 69 | } 70 | 71 | function noagent { 72 | # gpg-agent is buggy with 4K keys on cryptosticks, so we disable it: 73 | [[ -n "$GPG_AGENT_INFO" ]] && { 74 | export OLD_GPGAGENT="$GPG_AGENT_INFO" 75 | unset GPG_AGENT_INFO 76 | } 77 | } 78 | 79 | function reagent { 80 | # restore gpg-agent if it was running 81 | [[ -n "$OLD_GPGAGENT" ]] && { 82 | export GPG_AGENT_INFO="$OLD_GPGAGENT" 83 | unset OLD_GPGAGENT 84 | } 85 | } 86 | 87 | # use $1 to pass an alternative root-dir for the password store. 88 | # TODO proper parameter handling someday 89 | if [[ -n "$1" && -f "$1/.cfg" ]]; then 90 | data="$1" 91 | shift 1 92 | else 93 | data="$HOME/.pwd" 94 | fi 95 | # load keyid & salt 96 | source $data/.cfg 97 | [[ -z "$keyid" ]] && exit 1 98 | salt=${salt:-anti-rainbow-garbage} # this should be some random string 99 | 100 | # if $1 = host and $2 = user get host/user passwords 101 | # Todo fix parameter handling 102 | [[ "$#" -eq 3 ]] && { 103 | hosthash="$( { echo -n "$salt"; echo "$1"; } | /usr/bin/md5sum | cut -d' ' -f1 )" 104 | userhash="$( { echo -n "$salt"; echo "$2"; } | /usr/bin/md5sum | cut -d' ' -f1 )" 105 | noagent 106 | line=$(pwprompt | /usr/bin/gpg --batch --no-tty --quiet -d --passphrase-fd 0 $gpghome -d ~/.pwd/$hosthash/$userhash ) 107 | reagent 108 | echo -n "${line}" | cut -d" " -f2 | /usr/bin/xclip -i -selection clipboard 109 | exit 0 110 | } 111 | 112 | # find out title/url of active window 113 | windowid=$(/usr/bin/xdotool getactivewindow) 114 | title=$(/usr/bin/xdotool getwindowname $windowid | /bin/sed -e 's/^ *//g;s/ *$//g') 115 | case $title in 116 | *Pentadactyl|*Vimperator) title="$(xdoget "$title" Escape y)"; wintype=dactyl;; 117 | *Iceweasel|*Firefox) title="$(xdoget "$title" Escape ctrl+l ctrl+a ctrl+c)"; wintype=firefox;; 118 | *Chromium) title="$(xdoget "$title" Escape ctrl+l ctrl+a ctrl+c)"; wintype=chromium;; 119 | *Uzbl\ browser*) title="$(xdoget "title" Escape y u)"; wintype=uzbl;; 120 | luakit*) title="$(xdoget "title" shift+o Home ctrl+Right Right ctrl+shift+End ctrl+c Escape)"; wintype=luakit;; 121 | esac 122 | # get hash of title/url 123 | hash="$( { echo -n "$salt"; echo "$title"; } | /usr/bin/md5sum | cut -d' ' -f1 )" 124 | 125 | # if invoked with $1 = a 126 | # add a new random password with the current window 127 | [[ "$1" == "a" ]] && { 128 | pwd=$(pwgen) 129 | user=$(userprompt) 130 | userhash="$( { echo -n "$salt"; echo "$user"; } | /usr/bin/md5sum | cut -d' ' -f1 )" 131 | mkdir -p ~/.pwd/$hash 132 | [[ -f ~/.pwd/$hash/$userhash ]] && mv ~/.pwd/$hash/$userhash ~/.pwd/$hash/$userhash.$(date +%s) 133 | echo -n "$user $pwd" | /usr/bin/gpg --command-file <(pwprompt) --yes --no-tty --quiet $gpghome --sign --local-user $keyid --encrypt -r $keyid >~/.pwd/$hash/$userhash 134 | echo -n "$pwd" | /usr/bin/xclip -i -selection clipboard 135 | exit 0 136 | } 137 | 138 | # query all stored passwords for the current active window 139 | #echo "key=$title" >>~/.pwd/log 140 | [[ -d ~/.pwd/$hash ]] || exit 1 # no such host/label available 141 | 142 | noagent 143 | pass="$(pwprompt)" 144 | user="$(for key in ~/.pwd/$hash/* ; do 145 | fname="${key##*/}"; [[ "$fname" =~ .*\..* ]] && continue 146 | # todo adapt 147 | line=$(echo "$pass" | /usr/bin/gpg --batch --no-tty --quiet --passphrase-fd 0 $gpghome -d $key ) 148 | user="$(echo "${line}" | cut -d" " -f1)" 149 | echo "$user" 150 | sleep 0.2 151 | done | /usr/bin/dmenu)" 152 | 153 | [[ -n "$user" ]] && { 154 | userhash="$( { echo -n "$salt"; echo "$user"; } | /usr/bin/md5sum | cut -d' ' -f1)" 155 | line=$(echo "$pass" | /usr/bin/gpg --batch --no-tty --quiet --passphrase-fd 0 $gpghome -d ~/.pwd/$hash/$userhash ) 156 | echo -n "${line}" | cut -d" " -f2 | /usr/bin/xclip -i -selection clipboard 157 | [[ -n "$wintype" ]] && { 158 | case $wintype in 159 | dactyl) /usr/bin/xdotool key --window $windowid Escape g i ctrl+u ;; 160 | luakit) /usr/bin/xdotool key --window $windowid Escape g i Tab ctrl+u ;; 161 | firefox) /usr/bin/xdotool key --window $windowid Tab Tab Tab ;; 162 | chromium) /usr/bin/xdotool key --window $windowid Tab ;; 163 | esac 164 | /usr/bin/xdotool type --window $windowid "$user" 165 | /usr/bin/xdotool key --window $windowid Tab 166 | } 167 | } 168 | reagent 169 | --------------------------------------------------------------------------------