diff --git a/pyproject.toml b/pyproject.toml index a6f04d0..538b81c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "bw-get" -version = "1.0.1" +version = "1.1.0" authors = [ {name="Fabian van Koppen", email="f@bianvk.nl"} ] diff --git a/src/bw_get/bw_get.py b/src/bw_get/bw_get.py index 345c080..42f72e1 100755 --- a/src/bw_get/bw_get.py +++ b/src/bw_get/bw_get.py @@ -12,6 +12,21 @@ from subprocess import run, DEVNULL home = environ.get('HOME') +def parse_totp(totp: str) -> None|str: + try: + # Attempt to parse the TOTP URI + totp = pyotp.parse_uri(totp).now() + except Exception as e: + try: + # Attempt to create a TOTP object using the TOTP function + totp = pyotp.TOTP(totp).now() + except Exception as e: + # Return False if both attempts fail + totp = None + return totp + + + def check_lock() -> bool: check = run(['bw', 'unlock', '--check'], stdout=DEVNULL, stderr=DEVNULL) @@ -36,16 +51,20 @@ def get_password(search_string: Annotated[str, typer.Argument(help="The term to list_items_cmd = run(['bw', 'list', 'items', '--search', search_string], capture_output=True) items = json.loads(list_items_cmd.stdout) - + + search_string_lower = search_string.lower() # Filtering the list based on the search string filtered_list = [ - d for d in items if any( - search_string in str(value) for key, value in d.items() - if key != 'login' # Exclude the 'login' key entirely - ) or ( - 'login' in d and ( - search_string in str(d['login'].get('username', '')) or - search_string in str(d['login'].get('password', '')) + d for d in items + if d.get('type') == 1 and ( # Only passwords + any( + search_string_lower in str(value).lower() for key, value in d.items() + if key != 'login' # Exclude the 'login' key entirely + ) or ( + 'login' in d and ( + search_string_lower in str(d['login'].get('username', '')).lower() or + search_string_lower in str(d['login'].get('password', '')).lower() + ) ) ) ] @@ -54,7 +73,12 @@ def get_password(search_string: Annotated[str, typer.Argument(help="The term to if len(filtered_list) > 1: for item_index, item in enumerate(filtered_list): - choices.append(questionary.Choice(f"{item['name']} ({item['login']['username']})", item_index)) + if item.get('login') and item['login'].get('username'): + username = f" ({item['login']['username']})" + else: + username = "" + + choices.append(questionary.Choice(f"{item['name']}{username}", item_index)) chosen_index = questionary.select("Select item", choices, use_shortcuts=True).ask() elif len(filtered_list) == 1: @@ -73,9 +97,9 @@ def get_password(search_string: Annotated[str, typer.Argument(help="The term to print(f"username\t: {filtered_list[chosen_index]['login']['username']}") print(f"password\t: \033[34m\033[44m{filtered_list[chosen_index]['login']['password']}\033[0m") - if filtered_list[chosen_index]['login']['totp']: - totp = pyotp.parse_uri(filtered_list[chosen_index]['login']['totp']) - print(f"TOTP\t\t: {totp.now()}") + if filtered_list[chosen_index]['login']['totp'] and parse_totp(filtered_list[chosen_index]['login']['totp']): + totp = parse_totp(filtered_list[chosen_index]['login']['totp']) + print(f"TOTP\t\t: {totp}") try: import pyperclip