Skip to content

Commit

Permalink
Emphasize clipboard clearing warning (#213)
Browse files Browse the repository at this point in the history
* Emphasize clipboard clearing warning

* Fix failing tests after adding another pause

* Ignore some tests on Python 3.9 because of borked asyncio subprocess

* Minor type change
  • Loading branch information
remyroy authored Oct 19, 2024
1 parent 2867c87 commit 43c25ce
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 38 deletions.
3 changes: 3 additions & 0 deletions ethstaker_deposit/cli/existing_mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ethstaker_deposit.key_handling.key_derivation.mnemonic import (
reconstruct_mnemonic,
)
from ethstaker_deposit.utils import config
from ethstaker_deposit.utils.constants import (
MNEMONIC_LANG_OPTIONS,
WORD_LISTS_PATH,
Expand Down Expand Up @@ -118,6 +119,8 @@ def existing_mnemonic(ctx: click.Context, mnemonic: str, mnemonic_password: str,
ctx.obj.update({'mnemonic': mnemonic, 'mnemonic_password': mnemonic_password})
# Clear clipboard
try: # Failing this on headless Linux is expected
if not config.non_interactive:
click.pause(load_text(['msg_confirm_clipboard_clearing']))
pyperclip.copy(' ')
except Exception:
pass
Expand Down
15 changes: 13 additions & 2 deletions ethstaker_deposit/cli/new_mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,26 @@ def new_mnemonic(ctx: click.Context, mnemonic_language: str, **kwargs: Any) -> N
test_mnemonic = ''
while mnemonic != reconstruct_mnemonic(test_mnemonic, WORD_LISTS_PATH, mnemonic_language):
clear_terminal()
click.echo(load_text(['msg_mnemonic_presentation']))
click.echo(
load_text(['msg_mnemonic_presentation'])
+ '\n\n********************\n'
+ load_text(['msg_mnemonic_clipboard_warning'])
+ '\n********************'
)
click.echo('\n\n%s\n\n' % mnemonic)
click.pause(load_text(['msg_press_any_key']))

clear_terminal()
test_mnemonic = click.prompt(load_text(['msg_mnemonic_retype_prompt']) + '\n\n')
test_mnemonic = click.prompt(
load_text(['msg_mnemonic_retype_prompt'])
+ '\n\n********************\n'
+ load_text(['msg_mnemonic_clipboard_warning'])
+ '\n********************\n\n'
)
clear_terminal()
# Clear clipboard
try: # Failing this on headless Linux is expected
click.pause(load_text(['msg_confirm_clipboard_clearing']))
pyperclip.copy(' ')
except Exception:
pass
Expand Down
3 changes: 2 additions & 1 deletion ethstaker_deposit/intl/en/cli/existing_mnemonic.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"help": "Enter the index (key number) you wish to start generating more keys from. For example, if you've generated 4 keys in the past, you'd enter 4 here.",
"prompt": "Enter the index (key number) you wish to start generating more keys from. For example, if you've generated 4 keys in the past, you'd enter 4 here.",
"confirm": "Please repeat the validator start index to confirm"
}
},
"msg_confirm_clipboard_clearing": "WARNING: Your clipboard will be CLEARED. Press any key to clear the clipboard."
}
}
4 changes: 3 additions & 1 deletion ethstaker_deposit/intl/en/cli/new_mnemonic.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
},
"msg_mnemonic_presentation": "This is your mnemonic (seed phrase). Write it down and store it safely. It is the ONLY way to retrieve your deposit.",
"msg_press_any_key": "Press any key when you have written down your mnemonic.",
"msg_mnemonic_retype_prompt": "Please type your mnemonic (separated by spaces) to confirm you have written it down. You MUST write the mnemonic down, as the clipboard will be cleared after this step. Note: you only need to enter the first 4 letters of each word if you'd prefer."
"msg_mnemonic_retype_prompt": "Please type your mnemonic (separated by spaces) to confirm you have written it down. Note: you only need to enter the first 4 letters of each word if you'd prefer.",
"msg_mnemonic_clipboard_warning": "WARNING: You MUST write the mnemonic down, as the clipboard will be cleared after this step.",
"msg_confirm_clipboard_clearing": "WARNING: Your clipboard will be CLEARED. Press any key to clear the clipboard."
}
}
14 changes: 7 additions & 7 deletions tests/test_cli/test_existing_mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_existing_mnemonic_bls_withdrawal() -> None:
inputs = [
'TREZOR',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'2', '2', '5', 'mainnet', 'MyPasswordIs', 'MyPasswordIs']
'2', '2', '5', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -68,7 +68,7 @@ def test_existing_mnemonic_withdrawal_address() -> None:
inputs = [
'TREZOR',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'2', '2', '5', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', withdrawal_address, withdrawal_address]
'2', '2', '5', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', withdrawal_address, withdrawal_address, '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -126,7 +126,7 @@ def test_existing_mnemonic_withdrawal_address_bad_checksum() -> None:
'TREZOR',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'2', '2', '5', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
wrong_withdrawal_address, correct_withdrawal_address, correct_withdrawal_address
wrong_withdrawal_address, correct_withdrawal_address, correct_withdrawal_address, ''
]
data = '\n'.join(inputs)
arguments = [
Expand Down Expand Up @@ -184,7 +184,7 @@ def test_pbkdf2_new_mnemonic() -> None:
runner = CliRunner()
inputs = [
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'0', '0', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
'0', '0', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', '',
]
data = '\n'.join(inputs)
arguments = [
Expand Down Expand Up @@ -364,7 +364,7 @@ def test_existing_mnemonic_custom_testnet() -> None:
inputs = [
'TREZOR',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'2', '2', '5', 'MyPasswordIs', 'MyPasswordIs']
'2', '2', '5', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -409,7 +409,7 @@ def test_existing_mnemonic_multiple_languages() -> None:
inputs = [
'TREZOR',
'的 的 的 的 的 的 的 的 的 的 的 在', '1',
'2', '2', '5', 'MyPasswordIs', 'MyPasswordIs']
'2', '2', '5', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -454,7 +454,7 @@ def test_existing_mnemonic_multiple_languages_argument() -> None:
inputs = [
'TREZOR',
'的 的 的 的 的 的 的 的 的 的 的 在',
'2', '2', '5', 'MyPasswordIs', 'MyPasswordIs']
'2', '2', '5', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down
64 changes: 41 additions & 23 deletions tests/test_cli/test_new_mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:

runner = CliRunner()
inputs = ['english', 'english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--ignore_connectivity',
Expand Down Expand Up @@ -91,7 +91,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
runner = CliRunner()
withdrawal_address = '0x00000000219ab540356cBB839Cbe05303d7705Fa'
inputs = ['english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', withdrawal_address, withdrawal_address,
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -152,7 +152,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:

inputs = ['english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
wrong_withdrawal_address, correct_withdrawal_address, correct_withdrawal_address,
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -208,7 +208,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
runner = CliRunner()
withdrawal_address = '0x00000000219ab540356cBB839Cbe05303d7705Fa'
inputs = [withdrawal_address, 'english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -266,7 +266,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
runner = CliRunner()
withdrawal_address = '0x00000000219ab540356cBB839Cbe05303d7705Fa'
inputs = [withdrawal_address, 'english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -324,7 +324,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
runner = CliRunner()
withdrawal_address = '0x00000000219ab540356cBB839Cbe05303d7705Fa'
inputs = [withdrawal_address, 'english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -387,7 +387,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
runner = CliRunner()

inputs = ['english', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -448,7 +448,8 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
clean_key_folder(scrypt_folder_path)


@pytest.mark.skipif(sys.version_info[:2] == (3, 9) and sys.platform == "darwin", reason="breaks on macOS Python 3.9")
@pytest.mark.skipif(sys.version_info[:2] == (3, 9), reason=(
"asyncio subprocess is broken in different ways on 3.9 with https://github.com/python/cpython/issues/88050"))
@pytest.mark.asyncio
async def test_script_bls_withdrawal() -> None:
# Prepare folder
Expand Down Expand Up @@ -487,20 +488,28 @@ async def test_script_bls_withdrawal() -> None:
)

seed_phrase = ''
encoded_phrase = b''
parsing = False
mnemonic_json_file = os.path.join(os.getcwd(), 'ethstaker_deposit/../ethstaker_deposit/cli/', 'new_mnemonic.json')
msg_mnemonic_clipboard_warning = load_text(['msg_mnemonic_clipboard_warning'], mnemonic_json_file, 'new_mnemonic')
async for out in proc.stdout:
output = out.decode('utf-8').rstrip()
if output.startswith(load_text(['msg_mnemonic_presentation'], mnemonic_json_file, 'new_mnemonic')):
parsing = True
elif output.startswith(load_text(['msg_mnemonic_retype_prompt'], mnemonic_json_file, 'new_mnemonic')):
parsing = False
proc.stdin.write(encoded_phrase)
proc.stdin.write(b'\n')
elif output.startswith(load_text(['msg_confirm_clipboard_clearing'], mnemonic_json_file, 'new_mnemonic')):
proc.stdin.write(b'\n')
elif parsing:
seed_phrase += output
if len(seed_phrase) > 0:
encoded_phrase = seed_phrase.encode()
proc.stdin.write(encoded_phrase)
proc.stdin.write(b'\n')
if (
not output.startswith('********************')
and not output.startswith(msg_mnemonic_clipboard_warning)
):
seed_phrase += output
if len(seed_phrase) > 0:
encoded_phrase = seed_phrase.encode()
parsing = False

assert len(seed_phrase) > 0

Expand Down Expand Up @@ -536,7 +545,8 @@ async def test_script_bls_withdrawal() -> None:
clean_key_folder(my_folder_path)


@pytest.mark.skipif(sys.version_info[:2] == (3, 9) and sys.platform == "darwin", reason="breaks on macOS Python 3.9")
@pytest.mark.skipif(sys.version_info[:2] == (3, 9), reason=(
"asyncio subprocess is broken in different ways on 3.9 with https://github.com/python/cpython/issues/88050"))
@pytest.mark.asyncio
async def test_script_abbreviated_mnemonic() -> None:
# Prepare folder
Expand Down Expand Up @@ -575,21 +585,29 @@ async def test_script_abbreviated_mnemonic() -> None:
)

seed_phrase = ''
encoded_phrase = b''
parsing = False
mnemonic_json_file = os.path.join(os.getcwd(), 'ethstaker_deposit/../ethstaker_deposit/cli/', 'new_mnemonic.json')
msg_mnemonic_clipboard_warning = load_text(['msg_mnemonic_clipboard_warning'], mnemonic_json_file, 'new_mnemonic')
async for out in proc.stdout:
output = out.decode('utf-8').rstrip()
if output.startswith(load_text(['msg_mnemonic_presentation'], mnemonic_json_file, 'new_mnemonic')):
parsing = True
elif output.startswith(load_text(['msg_mnemonic_retype_prompt'], mnemonic_json_file, 'new_mnemonic')):
parsing = False
proc.stdin.write(encoded_phrase)
proc.stdin.write(b'\n')
elif output.startswith(load_text(['msg_confirm_clipboard_clearing'], mnemonic_json_file, 'new_mnemonic')):
proc.stdin.write(b'\n')
elif parsing:
seed_phrase += output
if len(seed_phrase) > 0:
abbreviated_mnemonic = ' '.join(abbreviate_words(seed_phrase.split(' ')))
encoded_phrase = abbreviated_mnemonic.encode()
proc.stdin.write(encoded_phrase)
proc.stdin.write(b'\n')
if (
not output.startswith('********************')
and not output.startswith(msg_mnemonic_clipboard_warning)
):
seed_phrase += output
if len(seed_phrase) > 0:
abbreviated_mnemonic = ' '.join(abbreviate_words(seed_phrase.split(' ')))
encoded_phrase = abbreviated_mnemonic.encode()
parsing = False

assert len(seed_phrase) > 0

Expand Down Expand Up @@ -639,7 +657,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:

runner = CliRunner()
inputs = ['english', 'english', '1', 'MyPasswordIs', 'MyPasswordIs',
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about']
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', '']
data = '\n'.join(inputs)
arguments = [
'--ignore_connectivity',
Expand Down
4 changes: 2 additions & 2 deletions tests/test_cli/test_regeneration.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
runner = CliRunner()
# Create index 0 and 1
my_password = "MyPasswordIs"
inputs = ['english', 'english', '2', 'mainnet', my_password, my_password, mock_mnemonic]
inputs = ['english', 'english', '2', 'mainnet', my_password, my_password, mock_mnemonic, '']
data = '\n'.join(inputs)
arguments = [
'--ignore_connectivity',
Expand Down Expand Up @@ -64,7 +64,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
inputs = [
'english',
mock_mnemonic,
'1', '1', '2', 'mainnet', 'MyPasswordIs', 'MyPasswordIs']
'1', '1', '2', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--ignore_connectivity',
Expand Down
4 changes: 2 additions & 2 deletions tests/test_deposit.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def _mock_socket_getaddrinfo(url, port):
runner = CliRunner()
inputs = [
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'0', '0', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs']
'0', '0', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down Expand Up @@ -131,7 +131,7 @@ def _mock_socket_getaddrinfo(url, port):
runner = CliRunner()
inputs = [
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'0', '0', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs']
'0', '0', '1', 'mainnet', 'MyPasswordIs', 'MyPasswordIs', '']
data = '\n'.join(inputs)
arguments = [
'--language', 'english',
Expand Down

0 comments on commit 43c25ce

Please sign in to comment.