From e02c552acb0f1c77527c242705b16b1c41745199 Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Thu, 8 Jul 2021 18:10:27 +0200 Subject: [PATCH] This commit adds initial support for init of local .password-store This is a start towards fixing #2 although it does not have git support yet, and does not import gpg/ssh keys. At least it's something :) --- README.md | 2 +- install.sh | 10 +++---- src/main.py | 58 ++++++++++++++++++++++++++++++++++-- src/pass_handler/__init__.py | 22 ++++++++++++-- 4 files changed, 80 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c904db1..98dbd43 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ To uninstall you can run: ``` ./install.sh -u ``` -The installer *should* theoretically work on all debian/mobian/ubuntu,arch/manjaro,alpine/postmarketos and fedora based distros. However, it has only been tested on x86_64 Debian and PostmarketOS on the PinePhone. +The installer *should* theoretically work on all debian/mobian/ubuntu,arch/manjaro and alpine/postmarketos based distros. However, it has only been tested on x86_64 Debian and PostmarketOS on the PinePhone. ## Usage Please make sure you [properly set up pass](https://git.zx2c4.com/password-store/about/#EXTENDED%20GIT%20EXAMPLE) and [gnupg](https://www.gnupg.org/gph/en/manual/c235.html#AEN243) first, if you use git for password storage, make sure to add a ssh-key so that you can push/pull without the need for entering a password. diff --git a/install.sh b/install.sh index 35bf388..d40fa92 100755 --- a/install.sh +++ b/install.sh @@ -12,16 +12,14 @@ elif [[ "${1}" == "-h" ]]; then fi if [[ -f /usr/bin/apk ]]; then # PostmarketOS/Alpine - sudo apk add py3-wxpython git gnupg pass + sudo apk add py3-wxpython py3-gnupg git gnupg pass elif [[ -f /usr/bin/apt ]]; then # Mobian/Debian/Ubuntu - sudo apt install python3-wxgtk4.0 git gnupg pass -elif [[ -f /usr/bin/dnf ]]; then # Fedora - sudo dnf install python3-wxpython4 git gnupg pass + sudo apt install python3-wxgtk4.0 python3-gnupg git gnupg pass elif [[ -f /usr/bin/pacman ]]; then # Arch/Manjaro - sudo pacman -S python-wxpython git gnupg pass + sudo pacman -S python-wxpython python-gnupg git gnupg pass else echo " This distribution is not supported by this installer. - manually install: wxpython git gnupg pass + manually install: wxpython python3-gnupg git gnupg pass and then copy passui to /usr/local/bin and passui.desktop to /usr/share/applications/" exit 1 fi diff --git a/src/main.py b/src/main.py index 86ced05..50b7f0f 100755 --- a/src/main.py +++ b/src/main.py @@ -7,6 +7,7 @@ from typing import Union import wx import wx.lib.scrolledpanel as scrolled +import gnupg from pass_handler import Pass, copy_to_clipboard, get_password_from_path, pass_pull, pass_push @@ -42,13 +43,18 @@ class PassUi(wx.Frame): """ super().__init__(*args, **kw) self.pass_handler: Pass = Pass() + self.gpg_handler: gnupg.GPG = gnupg.GPG() + self.gpg_key: str = str() # create a panel in the frame self.pnl: wx.lib.scrolledpanel.ScrolledPanel = scrolled.ScrolledPanel(self, -1, style=wx.VSCROLL) self.pnl.SetupScrolling() # and create a sizer to manage the layout of child widgets self.sizer: wx.BoxSizer = wx.BoxSizer(wx.VERTICAL) self.pnl.SetSizer(self.sizer) - self.add_buttons() + if self.pass_handler.is_init: + self.add_buttons() + else: + self.add_init() @redraw def add_buttons(self): @@ -82,6 +88,25 @@ class PassUi(wx.Frame): btn) index = index + 1 + @redraw + def add_init(self): + select_label: str = "Select GPG Key" + if self.gpg_key: + label: wx.StaticText = wx.StaticText(self.pnl, label="Selected GPG key:") + self.sizer.Add(label, 0, wx.EXPAND) # pylint: disable=no-member + choice: wx.StaticText = wx.StaticText(self.pnl, label=self.gpg_key) + self.sizer.Add(choice, 0, wx.EXPAND) # pylint: disable=no-member + select_label: str = "Select New GPG Key" + gpg_btn: wx.Button = wx.Button(self.pnl, label=select_label) + init_btn: wx.Button = wx.Button(self.pnl, label="Init Local Password Store") + self.sizer.Add(gpg_btn, 0, wx.EXPAND) # pylint: disable=no-member + self.sizer.Add(init_btn, 0, wx.EXPAND) # pylint: disable=no-member + self.Bind(wx.EVT_BUTTON, + lambda event: self.gpg_button_clicked(), gpg_btn) + if self.gpg_key: + self.Bind(wx.EVT_BUTTON, + lambda event: self.init_button_clicked(), init_btn) + def add_push_pull(self): """add_push_pull.""" push_btn: wx.Button = wx.Button(self.pnl, label="Push to remote") @@ -145,6 +170,24 @@ class PassUi(wx.Frame): btn.SetFont(font) return btn + def gpg_button_clicked(self): + """gpg_button_clicked. + + """ + private_keys: dict = self.gpg_handler.list_keys(True) + uid_list: list[str] = list() + for key in private_keys: + for uid in key['uids']: + uid_list.append(uid) + self.show_choice(uid_list, "Select GNUPG Key") + + def init_button_clicked(self): + """init_button_clicked. + + """ + self.pass_handler.pass_init(self.gpg_key) + self.add_buttons() + def password_button_clicked(self, index: int): """password_button_clicked. @@ -202,6 +245,18 @@ class PassUi(wx.Frame): self.pass_handler.save_to_pass(password, path, full_path) self.back_button_clicked() + @redraw + def show_choice(self, choices: list[str], name: str): + choice: wx.Choice = wx.Choice(self.pnl, choices=choices, name=name) + self.sizer.Add(choice, 0, wx.EXPAND) + self.Bind(wx.EVT_CHOICE, lambda event: self.choice_button_clicked(event), choice) + + def choice_button_clicked(self, event): + choice = event.GetEventObject() + self.gpg_key = choice.GetString(choice.GetSelection()) + print(self.gpg_key) + self.add_init() + @redraw def show_new_dialog(self): """show_new_dialog. @@ -326,7 +381,6 @@ class PassUi(wx.Frame): n_btn) self.add_push_pull() - if __name__ == '__main__': # When this module is run (not imported) then create the app, the # frame, show it, and start the event loop. diff --git a/src/pass_handler/__init__.py b/src/pass_handler/__init__.py index 2753a01..e1b40ef 100644 --- a/src/pass_handler/__init__.py +++ b/src/pass_handler/__init__.py @@ -8,11 +8,11 @@ class Pass: def __init__(self): self.top_dir: str = os.environ.get('PASSWORD_STORE_DIR') + self.is_init = False if not self.top_dir: self.top_dir = os.environ.get('HOME') + '/.password-store' - self.cur_dir: str = self.top_dir - self.cur_paths: list[str] = self.get_pass_paths() - self.cur_passwords: list[str] = self.get_pass_passwords() + if os.path.isdir(self.top_dir): + self.set_paths_on_init() def delete_password(self, path: str): """delete_password. @@ -67,6 +67,13 @@ class Pass: self.move_up() return True + def pass_init(self, gpg_key): + """pass_init. + + """ + run_command(['/usr/bin/pass', 'init', gpg_key]) + self.set_paths_on_init() + def save_to_pass(self, password, path, full_path): command1: list[str] = ['/bin/echo', password.rstrip("\n")] command2: list[str] = ['/usr/bin/pass', 'insert', '-m', path] @@ -74,6 +81,15 @@ class Pass: self.cur_paths = sorted([full_path] + self.cur_paths) self.cur_passwords = self.get_pass_passwords() + def set_paths_on_init(self): + """set_paths_on_init. + + """ + self.cur_dir: str = self.top_dir + self.cur_paths: list[str] = self.get_pass_paths() + self.cur_passwords: list[str] = self.get_pass_passwords() + self.is_init = True + def copy_to_clipboard(text) -> tuple[Union[str, bytes], Union[str, bytes]]: """copy_to_clipboard.