diff --git a/releases/Next-ChangeLog.md b/releases/Next-ChangeLog.md index eb6d2a51..b1bb3ded 100644 --- a/releases/Next-ChangeLog.md +++ b/releases/Next-ChangeLog.md @@ -7,6 +7,9 @@ This lists the new changes that have not yet been published in a normal release. - Bugfix: Delta Mode Trick PIN was never restored from backup - Bugfix: Proper error message for incorrect 7z headers - Bugfix: Exiting nickname entry with nickname already saved deleted previous nickname +- Bugfix: "Send Password" menu item inside Notes & Passwords visibility reversed +- Bugfix: Yikes when using "Send Password" on entry with password None field +- Bugfix: Do not show "Saving..." UX after failed Notes & Passwords import # Mk Specific Changes diff --git a/shared/notes.py b/shared/notes.py index eff14d65..e14a84f7 100644 --- a/shared/notes.py +++ b/shared/notes.py @@ -380,7 +380,7 @@ class PasswordContent(NoteContentBase): # if self.misc: rv.append(MenuItem('↳ (notes)', f=self.view)) rv += [ MenuItem('View Password', f=self.view_pw), - MenuItem('Send Password', f=self.send_pw, predicate=lambda: settings.get('du', True)), + MenuItem('Send Password', f=self.send_pw, predicate=lambda: not settings.get('du', 0)), ] if not readonly: rv += [ @@ -468,7 +468,8 @@ class PasswordContent(NoteContentBase): if self.idx == -1: # prompt for password only on new records. - self.password = await get_a_password(self.password) + # can be None if CANCEL is pressed - handle, Send Password requires string + self.password = await get_a_password(self.password) or "" site = await ux_input_text(self.site, max_len=ONE_LINE, scan_ok=True, confirm_exit=False, prompt='Website', placeholder='(optional)') @@ -664,8 +665,9 @@ async def import_from_other(menu, *a): records = json.load(open(fn, 'rt')) # We have some JSON, parsed now. - await import_from_json(records) - + ok = await import_from_json(records) + if not ok: return + await ux_dramatic_pause('Saved.', 3) menu.update_contents() @@ -683,6 +685,7 @@ async def import_from_json(records): settings.set('notes', was) settings.set('secnap', True) settings.save() + return True except Exception as e: await ux_show_story(title="Failure", msg=str(e) + '\n\n' + problem_file_line(e)) diff --git a/testing/test_notes.py b/testing/test_notes.py index b5441328..260ffadb 100644 --- a/testing/test_notes.py +++ b/testing/test_notes.py @@ -672,6 +672,61 @@ def test_sign_note_body(msg, addr_fmt, acct, need_some_notes, sign_msg_from_text(msg, addr_fmt, acct, False, 0, way) +def test_send_password_menu_item(need_some_passwords, goto_notes, cap_menu, pick_menu_item, + settings_set, settings_remove, press_cancel): + # covers regression where "Send Password" menu item was only shown when USB was disabled + need_some_passwords() + + settings_set('du', 1) + goto_notes() + pick_menu_item('1: A') + time.sleep(.2) + m = cap_menu() + assert 'Send Password' not in m + press_cancel() + + settings_set('du', 0) + goto_notes() + pick_menu_item('1: A') + time.sleep(.2) + m = cap_menu() + assert 'Send Password' in m + for _ in range(3): + press_cancel() + + +@pytest.mark.onetime +def test_password_cancel_stores_empty_not_none(goto_notes, need_keypress, press_select, + press_cancel, enter_text, settings_get, + settings_set, cap_screen, pick_menu_item): + # canceling the password field when creating a new password entry stored + # None instead of ''. EmulatedKeyboard.can_type(None) then raised + # TypeError: 'NoneType' object is not iterable when "Send Password" was selected. + # + settings_set('secnap', True) + settings_set('notes', []) + + goto_notes('New Password') + enter_text('cancel-pw-test') # title + press_select() # skip username + press_cancel() # cancel password field - bug, stores None + press_select() # skip site + press_cancel() # exit misc + + time.sleep(0.2) + + goto_notes() + pick_menu_item('1: cancel-pw-test') + pick_menu_item('Send Password') + time.sleep(.5) + + scr = cap_screen() + assert 'Traceback' not in scr + assert "Place mouse at" in scr + for _ in range(5): + press_cancel() + + @pytest.mark.parametrize("chain", ["BTC", "XTN"]) @pytest.mark.parametrize("change", [True, False]) @pytest.mark.parametrize("idx", [None, 0, 9999])