diff --git a/info.plist b/info.plist index a8e629a..e99d87f 100644 --- a/info.plist +++ b/info.plist @@ -58,6 +58,19 @@ + E51C31A6-DF82-4087-BE7B-A7A588C49BCA + + + destinationuid + FD54DB02-354D-478D-A10D-AB7D69256AD9 + modifiers + 0 + modifiersubtext + + vitoclose + + + createdby Przemek KamiƄski @@ -76,6 +89,8 @@ alfredfiltersresultsmatchmode 0 + argumenttreatemptyqueryasnil + argumenttrimmode 0 argumenttype @@ -114,7 +129,7 @@ uid 7DD3BDE5-A157-42E5-9376-F681FB50A4EE version - 2 + 3 config @@ -147,14 +162,14 @@ clipboardtext {query} transient - + type alfred.workflow.output.clipboard uid C7B97C94-3D0B-471E-96EE-A441A1FAB184 version - 2 + 3 config @@ -207,6 +222,8 @@ alfredfiltersresultsmatchmode 0 + argumenttreatemptyqueryasnil + argumenttrimmode 0 argumenttype @@ -245,7 +262,7 @@ uid 967E625E-D870-4298-9A7A-97C043740D99 version - 2 + 3 config @@ -270,10 +287,81 @@ version 2 + + config + + concurrently + + escaping + 102 + script + /usr/local/bin/bash pass-autocomplete.sh "{query}" + scriptargtype + 0 + scriptfile + + type + 0 + + type + alfred.workflow.action.script + uid + FD54DB02-354D-478D-A10D-AB7D69256AD9 + version + 2 + + + config + + alfredfiltersresults + + alfredfiltersresultsmatchmode + 0 + argumenttreatemptyqueryasnil + + argumenttrimmode + 0 + argumenttype + 0 + escaping + 102 + keyword + passa + queuedelaycustom + 3 + queuedelayimmediatelyinitially + + queuedelaymode + 0 + queuemode + 1 + runningsubtext + + script + python pass-filter.py "{query}" + scriptargtype + 0 + scriptfile + + subtext + + title + Autotype + type + 0 + withspace + + + type + alfred.workflow.input.scriptfilter + uid + E51C31A6-DF82-4087-BE7B-A7A588C49BCA + version + 3 + readme - A workflow to integrate with Pass - the standard Unix password manager. -See the README file at https://github.com/CGenie/alfred-pass for more info. + uidata 06C9C4A9-38CE-441A-8D06-E2F2D8B39B60 @@ -325,6 +413,20 @@ See the README file at https://github.com/CGenie/alfred-pass for more info.ypos 60 + E51C31A6-DF82-4087-BE7B-A7A588C49BCA + + xpos + 295 + ypos + 430 + + FD54DB02-354D-478D-A10D-AB7D69256AD9 + + xpos + 505 + ypos + 430 + version 0.3.4 diff --git a/pass-autocomplete.sh b/pass-autocomplete.sh new file mode 100755 index 0000000..d50399c --- /dev/null +++ b/pass-autocomplete.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +set -e + + +QUERY=$1 +PATH=/usr/local/bin:$PATH + +AUTOTYPE_field='autotype' +default_autotype="user :tab pass" +URL_field='url' +USERNAME_field='user' + +allData="$(pass show $QUERY)" + +function doType { + echo "tell application \"System Events\" to keystroke \"$1\"" | osascript +} + +function doStroke { + echo "tell application \"System Events\" to key code $1" | osascript +} + +declare -A stuff +pass_key_value=$(printf '%s\n' "${allData}" | tail -n+2 | grep ': ') +while read -r LINE; do + _id="${LINE%%: *}" + _val="${LINE#* }" + stuff["${_id}"]=${_val} +done < <(printf '%s\n' "${pass_key_value}") + +password="${allData%%$'\n'*}" +stuff["pass"]=${password} + +if test "${stuff['autotype']+autotype}"; then + : +else + stuff["autotype"]="${USERNAME_field} :tab pass" +fi + +pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)" + +for word in ${stuff["$AUTOTYPE_field"]}; do + case "$word" in + ":tab") doStroke 48;; + ":space") doStroke 49;; + ":delay") sleep "${delay}";; + ":enter") doStroke 36;; + *) doType "${stuff[${word}]}";; + esac +done + diff --git a/pass-filter.py b/pass-filter.py index 4728377..e1bc9a3 100755 --- a/pass-filter.py +++ b/pass-filter.py @@ -4,57 +4,35 @@ import os import sys import string - -fuzzysearch = True -try: - from fuzzywuzzy import process -except: - fuzzysearch = False +import glob QUERY = sys.argv[1] HOME = os.environ['HOME'] -PASS_DIR = os.environ.get('PASSWORD_STORE_DIR',os.path.join(HOME, '.password-store/')) - +PASS_DIR = os.environ.get('PASSWORD_STORE_DIR', os.path.join(HOME, '.password-store/')) # TODO: list_passwords creates cache of passwords for first time def list_passwords(): - ret = [] + ret = [f for f in glob.glob(PASS_DIR+ "/**/*.gpg")] + replaced = list(map(lambda x : x.replace('.gpg','').replace(PASS_DIR, ''), ret)) - for root, dirnames, filenames in os.walk(PASS_DIR, True, None, True): - for filename in fnmatch.filter(filenames, '*.gpg'): - ret.append(os.path.join(root, filename.replace('.gpg','')).replace(PASS_DIR, '')) - return sorted(ret, key=lambda s: s.lower()) + #for root, dirnames, filenames in os.walk(PASS_DIR): + # for filename in fnmatch.filter(filenames, '*.gpg'): + # ret.append(os.path.join(root, filename.replace('.gpg','')).replace(PASS_DIR, '')) + return sorted(replaced, key=lambda s: s.lower()) def search_passwords(query): - ''' Search passwords using the Fuzzy search method if fuzzywuzzy is available, - or default to the filter-based search otherwise''' - if fuzzysearch: - return search_passwords_fuzzy(query) - return search_passwords_filter(query) - - -def search_passwords_fuzzy(query): - ''' Search passwords using the Fuzzy search method using fuzzywuzzy''' - passwords = list_passwords() - return [entry[0] for entry in process.extract(query, passwords)] - - -def search_passwords_filter(query): - ''' Search passwords using the filter-based search, which doesn't require fuzzywuzzy''' ret = [] terms = filter(lambda x: x, query.lower().split()) passwords = list_passwords() - for password in passwords: for t in terms: if t not in password.lower(): break else: ret.append(password) - return ret