diff --git a/scripts/passui b/scripts/passui index 2801adb..2ffbb49 100755 --- a/scripts/passui +++ b/scripts/passui @@ -11,7 +11,7 @@ import wx.lib.scrolledpanel as scrolled import wx.lib.dialogs as dialogs import gnupg -from passui import Pass, copy_to_clipboard, get_password_from_path, pass_pull, pass_push, run_command +from pass_handler import Pass, copy_to_clipboard, get_password_from_path, pass_pull, pass_push, run_command class PassUi(wx.Frame): diff --git a/setup.py b/setup.py index 9b05754..dca9f89 100644 --- a/setup.py +++ b/setup.py @@ -21,8 +21,8 @@ setuptools.setup( "License :: OSI Approved :: GPL-3.0", "Operating System :: OS Independent", ], - package_dir={"passui": "lib"}, - packages=setuptools.find_packages(where="lib"), + package_dir={"": "src"}, + packages=setuptools.find_packages(where="src"), python_requires=">=3.9", scripts=["scripts/passui"], ) diff --git a/src/pass_handler/__init__.py b/src/pass_handler/__init__.py new file mode 100644 index 0000000..05980ee --- /dev/null +++ b/src/pass_handler/__init__.py @@ -0,0 +1,151 @@ +#!/usr/bin/python3 +import os +import subprocess +from typing import Union + + +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' + if os.path.isdir(self.top_dir): + self.set_paths_on_init() + + def delete_password(self, path: str): + """delete_password. + + :param path: str + """ + command1: list[str] = ['/usr/bin/pass', 'rm', '-f', path] + run_command(command1) + self.move_up() + self.cur_paths = self.get_pass_paths() + self.cur_passwords = self.get_pass_passwords() + + def get_pass_path_from_index(self, index: int, path_type: str = "path") -> str: + """get_pass_path_from_index. + + :param index: int + :param path_type: str, default: "path" + """ + if path_type == "password": + result: str = self.cur_passwords[index] + else: + result: str = self.cur_paths[index] + return result.replace(self.top_dir, '').replace('.gpg', '') + + def get_pass_passwords(self) -> list[str]: + """get_pass_passwords.""" + passwords: list[str] = list() + for m_file in os.listdir(self.cur_dir): + if m_file.endswith(".gpg"): + passwords.append(os.path.join(self.cur_dir, m_file)) + passwords = sorted(passwords) + return passwords + + def get_pass_paths(self) -> list[str]: + """get_pass_paths.""" + dirs: list[str] = list() + if self.cur_dir != self.top_dir: + dirs.append(self.cur_dir) + for c_dir in os.listdir(self.cur_dir): + if os.path.isdir(os.path.join(self.cur_dir, + c_dir)) and c_dir != ".git": + dirs.append(os.path.join(self.cur_dir, c_dir)) + dirs = sorted(dirs) + return dirs + + def move_up(self) -> bool: + """move_up.""" + if self.cur_dir == self.top_dir: + return True + if not os.path.isdir(self.cur_dir): + self.cur_dir = os.path.abspath(os.path.join(self.cur_dir, os.pardir)) + self.move_up() + return True + + def pass_init(self, gpg_key: str, git_repo: Union[None, str] = None): + """pass_init. + + """ + if git_repo: + run_command(['/usr/bin/git', 'clone', git_repo, self.top_dir]) + else: + 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] + run_command(command1, command2) + 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. + + :param text: + """ + password: str = text.split('\n')[0] + command1: list[str] = ['/bin/echo', password] + command2: list[str] = ['/usr/bin/wl-copy'] + result: tuple[Union[str, bytes], Union[str, bytes]] = run_command(command1, command2) + return result + + +def get_password_from_path(pass_path) -> str: + """get_password_from_path. + + :param pass_path: + """ + result: tuple[Union[str, bytes], Union[str, bytes]] = run_command(['/usr/bin/pass', 'show', pass_path]) + password: str = result[0].decode() + return password + + +def pass_pull(): + """pass_pull. + + """ + run_command(['/usr/bin/pass', 'git', 'pull']) + + +def pass_push(): + """pass_push. + + """ + run_command(['/usr/bin/pass', 'git', 'push']) + + +def run_command(command1, command2=None) -> tuple[Union[str, bytes], Union[str, bytes]]: + """Run a command on system and capture result + + :param command1: + :param command2: + """ + process1: subprocess.Popen = subprocess.Popen(command1, + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + # If there is a second command it is taken to be a pipeline + if command2: + subprocess.Popen(command2, + shell=False, + stdin=process1.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + process1.stdout.close() + return process1.communicate()