Re: pass - консольный менеджер паролей

Ответ на комментарий от btimofeev
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()

tuple (2024-10-19 08:42:54) [Ответить]
Предыдущее сообщение Следующее сообщение