aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorGravatar √Čtienne Deparis 2017-02-06 19:24:33 +0100
committerGravatar √Čtienne Deparis 2018-08-09 19:03:46 +0200
commitcad151ccb018242ef6434010474e0108949a77c7 (patch)
tree08397db29b1560eeb68297eec9559c0a4299ebb6
parenta57514c1d2423e4aaceaab2661a91c05e1ad61ee (diff)
downloadpassword-store-cad151ccb018242ef6434010474e0108949a77c7.tar.gz
password-store-cad151ccb018242ef6434010474e0108949a77c7.tar.xz
password-store-cad151ccb018242ef6434010474e0108949a77c7.zip
feat: Add passrofi
-rwxr-xr-xcontrib/rofi/passrofi.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/contrib/rofi/passrofi.py b/contrib/rofi/passrofi.py
new file mode 100755
index 0000000..02126e8
--- /dev/null
+++ b/contrib/rofi/passrofi.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import shlex
+import shutil
+import argparse
+import subprocess
+from collections import OrderedDict
+from xdg.BaseDirectory import xdg_cache_home
+
+
+default_rofi_command = "rofi -dmenu -p pass: -location 6 " \
+ "-no-case-sensitive -lines 5 -width 100"
+passdir = os.getenv("PASSWORD_STORE_DIR",
+ os.path.expanduser("~/.password-store"))
+
+
+class PassRofi():
+ def __init__(self, rofi_command, must_type=False):
+ self.cachefile = os.path.join(xdg_cache_home, "passrofi.history")
+ self.rofi_cmd = rofi_command
+ self.type_pass = must_type
+ self.init_history()
+
+ def run(self):
+ loc_history = list(self.history.keys())
+ loc_pass_list = [p for p in self.password_list()
+ if p not in loc_history]
+ whole_list = loc_history + loc_pass_list
+ selected_pass = self.run_rofi(whole_list)
+
+ if selected_pass == "":
+ return
+
+ if selected_pass in self.history:
+ self.history[selected_pass] += 1
+ else:
+ self.history[selected_pass] = 0
+
+ self.history = sorted(self.history.items(), key=lambda x: x[0])
+ self.history.sort(key=lambda x: x[1], reverse=True)
+
+ with open(self.cachefile, "w") as f:
+ for line in self.history:
+ f.write("{1} {0}\n".format(*line))
+
+ if self.type_pass:
+ self.type_password(selected_pass)
+ else:
+ subprocess.run(
+ ["pass", "show", "-c", selected_pass],
+ stdout=subprocess.DEVNULL)
+
+ def init_history(self):
+ loc_history = []
+ if os.path.isfile(self.cachefile):
+ with open(self.cachefile, "r") as f:
+ for line in f:
+ ld = line.split()
+ if len(ld) != 2:
+ continue
+ loc_history.append((ld[1], int(ld[0])))
+ self.history = OrderedDict(loc_history)
+
+ def password_list(self):
+ pass_list = []
+ passdirlen = len(passdir) + 1
+ raw_pass_list = subprocess.run(
+ ["find", passdir, "-type", "f", "-name", "*.gpg"],
+ check=True, stdout=subprocess.PIPE
+ ).stdout.decode().split("\n")
+ for line in raw_pass_list:
+ pass_list.append(line[passdirlen:-4])
+ return pass_list
+
+ def run_rofi(self, options):
+ cmd = subprocess.Popen(shlex.split(self.rofi_cmd),
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, _ = cmd.communicate("\n".join(options).encode())
+ return stdout.decode().strip()
+
+ def type_password(self, pass_name):
+ password = subprocess.run(
+ ["pass", "show", pass_name],
+ check=True, stdout=subprocess.PIPE
+ ).stdout.decode().split("\n")
+ subprocess.run(
+ ["xdotool", "type", "--clearmodifiers",
+ password[0].strip()])
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="rofi interface for pass")
+ parser.add_argument("-r", "--rofi", default=default_rofi_command,
+ help="rofi -dmenu command, executed within a shell")
+ parser.add_argument("-t", "--type-pass",
+ default=False,
+ action="store_true",
+ help="try to directly type the password in "
+ "the focused window (require xdotool)")
+
+ args = parser.parse_args()
+
+ should_type = args.type_pass
+ if should_type and not bool(shutil.which("xdotool")):
+ print("xdotool is required", file=sys.stderr)
+ should_type = False
+
+ if not bool(shutil.which("rofi")):
+ print("rofi is required", file=sys.stderr)
+ sys.exit(1)
+
+ pr = PassRofi(args.rofi, should_type)
+ pr.run()