btimofeev> Я использую скрипт https://github.com/carnager/rofi-pass , который позволяет искать и копировать логины\пароли через rofi (https://github.com/davatorium/rofi )
С помощью rofi работает у меня сторонний скрипт bemoji для выбора эмодзи из UTF-8:
https://github.com/marty-oehme/bemoji .
Кстати, вот сам скрипт "pypassmenu" на текущий момент. Пусть под лицензией UNLICENSE. Далёк от идеала, но может кто вдохновится или будет интересно.
#!/usr/bin/env python
import os
import re
import sys
import logging
from time import sleep
from pathlib import Path
from subprocess import Popen, PIPE
from argparse import ArgumentParser
class PassFile:
def __init__(self, name: str, content: str):
self.name = name
self._lines: list[str] = content.split('\n')
self._fields: dict[str, str] = {}
for line in self._lines:
m = re.match(r'(.+): (.+)', line)
if m:
self._fields[m.group(1)] = m.group(2)
logging.info(f'Created PassFile instance of {name}')
logging.debug(f'PassFile fields: {self._fields}')
@property
def password(self) -> str:
return self._lines[0]
def _get_field(self, field: str) -> str:
return self._fields[field]
@property
def email(self) -> str:
try:
logging.debug('Trying to find "email" field')
return self._get_field('email')
except KeyError:
logging.debug('Falling back to "e-mail" field')
return self._get_field('e-mail')
@property
def login(self) -> str:
try:
logging.debug('Trying to find "login" field')
return self._get_field('login')
except KeyError:
logging.debug('Falling back to e(-)mail field')
return self.email
def fetch_passfiles() -> dict[str,Path]:
store_path = Path(os.getenv('PASSWORD_STORE_DIR') or
os.getenv('HOME') + '/.password-store')
gpg_files = list(store_path.glob('**/*.gpg'))
gpg_files_dict = {}
for filepath in gpg_files:
relative_filepath = str(filepath.relative_to(store_path))
gpg_files_dict[re.sub(r'\.gpg$', '', relative_filepath)] = filepath
return gpg_files_dict
def choose_passfile_with_dmenu(gpg_files_dict: dict[str,Path]) -> tuple[str, Path]:
p = Popen(['dmenu'], stdout=PIPE, stdin=PIPE, text=True)
index = '\n'.join([key for key in gpg_files_dict])
stdout = p.communicate(input=index)[0]
choosen_filename = stdout.strip()
return choosen_filename, gpg_files_dict[choosen_filename]
def fetch_passfile_by_path(filename: str, filepath: Path) -> PassFile:
p = Popen(['gpg', '-d', '--quiet', str(filepath)], stdout=PIPE, text=True)
return PassFile(filename, p.stdout.read().strip())
def copy_to_clipboard(text: str):
p = Popen(['xclip', '-selection', 'clipboard'], stdin=PIPE, text=True)
p.communicate(input=text)
logging.info('Clipboard was written')
logging.debug(f'Clipboard content: {text}')
def clear_clipboard():
logging.debug('Clipboard cleared!')
copy_to_clipboard('')
def notify(header: str, body: str):
Popen(['notify-send', header, body])
logging.info('Notification sent')
logging.debug(f'Notification content:\n{header=}\n{body=}')
def main():
parser = ArgumentParser(prog='pypassmenu',
description='Improved passmenu written in python')
supported_fields = ( 'password', 'login', 'email', )
parser.add_argument('field', type=str, choices=supported_fields,
default=supported_fields[0], help='Obtained field')
args = parser.parse_args()
# logging.basicConfig(level=logging.DEBUG)
filename, filepath = choose_passfile_with_dmenu(fetch_passfiles())
pass_ = fetch_passfile_by_path(filename, filepath)
important_value = 'something'
try:
match args.field:
case 'password':
important_value = pass_.password
case 'login':
important_value = pass_.login
case 'email':
important_value = pass_.email
except KeyError:
notify('Не удалось найти поле',
f'pypassmenu: выбранное поле не найдено в {pass_.name}')
sys.exit(1)
copy_to_clipboard(important_value)
sleep(20)
clear_clipboard()
if __name__ == '__main__':
main()