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 :)
This commit is contained in:
parent
7f43e80c26
commit
e02c552acb
4 changed files with 80 additions and 12 deletions
|
@ -20,7 +20,7 @@ To uninstall you can run:
|
||||||
```
|
```
|
||||||
./install.sh -u
|
./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
|
## 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.
|
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.
|
||||||
|
|
10
install.sh
10
install.sh
|
@ -12,16 +12,14 @@ elif [[ "${1}" == "-h" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f /usr/bin/apk ]]; then # PostmarketOS/Alpine
|
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
|
elif [[ -f /usr/bin/apt ]]; then # Mobian/Debian/Ubuntu
|
||||||
sudo apt install python3-wxgtk4.0 git gnupg pass
|
sudo apt install python3-wxgtk4.0 python3-gnupg git gnupg pass
|
||||||
elif [[ -f /usr/bin/dnf ]]; then # Fedora
|
|
||||||
sudo dnf install python3-wxpython4 git gnupg pass
|
|
||||||
elif [[ -f /usr/bin/pacman ]]; then # Arch/Manjaro
|
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
|
else
|
||||||
echo " This distribution is not supported by this installer.
|
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/"
|
and then copy passui to /usr/local/bin and passui.desktop to /usr/share/applications/"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
56
src/main.py
56
src/main.py
|
@ -7,6 +7,7 @@ from typing import Union
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
import wx.lib.scrolledpanel as scrolled
|
import wx.lib.scrolledpanel as scrolled
|
||||||
|
import gnupg
|
||||||
|
|
||||||
from pass_handler import Pass, copy_to_clipboard, get_password_from_path, pass_pull, pass_push
|
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)
|
super().__init__(*args, **kw)
|
||||||
self.pass_handler: Pass = Pass()
|
self.pass_handler: Pass = Pass()
|
||||||
|
self.gpg_handler: gnupg.GPG = gnupg.GPG()
|
||||||
|
self.gpg_key: str = str()
|
||||||
# create a panel in the frame
|
# create a panel in the frame
|
||||||
self.pnl: wx.lib.scrolledpanel.ScrolledPanel = scrolled.ScrolledPanel(self, -1, style=wx.VSCROLL)
|
self.pnl: wx.lib.scrolledpanel.ScrolledPanel = scrolled.ScrolledPanel(self, -1, style=wx.VSCROLL)
|
||||||
self.pnl.SetupScrolling()
|
self.pnl.SetupScrolling()
|
||||||
# and create a sizer to manage the layout of child widgets
|
# and create a sizer to manage the layout of child widgets
|
||||||
self.sizer: wx.BoxSizer = wx.BoxSizer(wx.VERTICAL)
|
self.sizer: wx.BoxSizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
self.pnl.SetSizer(self.sizer)
|
self.pnl.SetSizer(self.sizer)
|
||||||
|
if self.pass_handler.is_init:
|
||||||
self.add_buttons()
|
self.add_buttons()
|
||||||
|
else:
|
||||||
|
self.add_init()
|
||||||
|
|
||||||
@redraw
|
@redraw
|
||||||
def add_buttons(self):
|
def add_buttons(self):
|
||||||
|
@ -82,6 +88,25 @@ class PassUi(wx.Frame):
|
||||||
btn)
|
btn)
|
||||||
index = index + 1
|
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):
|
def add_push_pull(self):
|
||||||
"""add_push_pull."""
|
"""add_push_pull."""
|
||||||
push_btn: wx.Button = wx.Button(self.pnl, label="Push to remote")
|
push_btn: wx.Button = wx.Button(self.pnl, label="Push to remote")
|
||||||
|
@ -145,6 +170,24 @@ class PassUi(wx.Frame):
|
||||||
btn.SetFont(font)
|
btn.SetFont(font)
|
||||||
return btn
|
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):
|
def password_button_clicked(self, index: int):
|
||||||
"""password_button_clicked.
|
"""password_button_clicked.
|
||||||
|
|
||||||
|
@ -202,6 +245,18 @@ class PassUi(wx.Frame):
|
||||||
self.pass_handler.save_to_pass(password, path, full_path)
|
self.pass_handler.save_to_pass(password, path, full_path)
|
||||||
self.back_button_clicked()
|
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
|
@redraw
|
||||||
def show_new_dialog(self):
|
def show_new_dialog(self):
|
||||||
"""show_new_dialog.
|
"""show_new_dialog.
|
||||||
|
@ -326,7 +381,6 @@ class PassUi(wx.Frame):
|
||||||
n_btn)
|
n_btn)
|
||||||
self.add_push_pull()
|
self.add_push_pull()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# When this module is run (not imported) then create the app, the
|
# When this module is run (not imported) then create the app, the
|
||||||
# frame, show it, and start the event loop.
|
# frame, show it, and start the event loop.
|
||||||
|
|
|
@ -8,11 +8,11 @@ class Pass:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.top_dir: str = os.environ.get('PASSWORD_STORE_DIR')
|
self.top_dir: str = os.environ.get('PASSWORD_STORE_DIR')
|
||||||
|
self.is_init = False
|
||||||
if not self.top_dir:
|
if not self.top_dir:
|
||||||
self.top_dir = os.environ.get('HOME') + '/.password-store'
|
self.top_dir = os.environ.get('HOME') + '/.password-store'
|
||||||
self.cur_dir: str = self.top_dir
|
if os.path.isdir(self.top_dir):
|
||||||
self.cur_paths: list[str] = self.get_pass_paths()
|
self.set_paths_on_init()
|
||||||
self.cur_passwords: list[str] = self.get_pass_passwords()
|
|
||||||
|
|
||||||
def delete_password(self, path: str):
|
def delete_password(self, path: str):
|
||||||
"""delete_password.
|
"""delete_password.
|
||||||
|
@ -67,6 +67,13 @@ class Pass:
|
||||||
self.move_up()
|
self.move_up()
|
||||||
return True
|
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):
|
def save_to_pass(self, password, path, full_path):
|
||||||
command1: list[str] = ['/bin/echo', password.rstrip("\n")]
|
command1: list[str] = ['/bin/echo', password.rstrip("\n")]
|
||||||
command2: list[str] = ['/usr/bin/pass', 'insert', '-m', path]
|
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_paths = sorted([full_path] + self.cur_paths)
|
||||||
self.cur_passwords = self.get_pass_passwords()
|
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]]:
|
def copy_to_clipboard(text) -> tuple[Union[str, bytes], Union[str, bytes]]:
|
||||||
"""copy_to_clipboard.
|
"""copy_to_clipboard.
|
||||||
|
|
Loading…
Add table
Reference in a new issue