You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
4.9 KiB

#!/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:
"""
clip_command = ['/usr/bin/wl-copy']
if not os.path.isfile(clip_command[0]):
clip_command = ['xclip', '-selection', 'c']
password: str = text.split('\n')[0]
command1: list[str] = ['/bin/echo', password]
command2: list[str] = clip_command
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])
if type(result[0]) == type(bytes()):
password: str = result[0].decode()
else:
password: str = result[0]
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()