diff --git a/README.md b/README.md index 40639994..22b4062f 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,15 @@ - - [Introduction](#introduction) - [Tutorial for users](#tutorial-for-users) - [Build requirements](#build-requirements) - [For Linux or MacOS users](#for-linux-or-macos-users) + - [File Permissions](#file-permissions) - [Option 1. Download binary executable file](#option-1-download-binary-executable-file) - [Step 1. Installation](#step-1-installation) - [Step 2. Create keys and `deposit_data-*.json`](#step-2-create-keys-and-deposit_data-json) + - [language Argument](#language-argument) - [Commands](#commands) - [`new-mnemonic` Arguments](#new-mnemonic-arguments) - [`existing-mnemonic` Arguments](#existing-mnemonic-arguments) @@ -19,6 +20,7 @@ - [Step 0. Python version checking](#step-0-python-version-checking) - [Step 1. Installation](#step-1-installation-1) - [Step 2. Create keys and `deposit_data-*.json`](#step-2-create-keys-and-deposit_data-json-1) + - [Language Argument](#language-argument) - [Commands](#commands-1) - [Arguments](#arguments) - [Successful message](#successful-message-1) @@ -26,6 +28,7 @@ - [Step 0. Python version checking](#step-0-python-version-checking-1) - [Step 1. Installation](#step-1-installation-2) - [Step 2. Create keys and `deposit_data-*.json`](#step-2-create-keys-and-deposit_data-json-2) + - [Language Argument](#language-argument-1) - [Commands](#commands-2) - [Arguments](#arguments-1) - [Option 4. Use Docker image](#option-4-use-docker-image) @@ -37,18 +40,21 @@ - [Option 1. Download binary executable file](#option-1-download-binary-executable-file-1) - [Step 1. Installation](#step-1-installation-3) - [Step 2. Create keys and `deposit_data-*.json`](#step-2-create-keys-and-deposit_data-json-4) + - [Language Argument](#language-argument-2) - [Commands](#commands-3) - [Arguments](#arguments-3) - [Option 2. Build `deposit-cli` with native Python](#option-2-build-deposit-cli-with-native-python-1) - [Step 0. Python version checking](#step-0-python-version-checking-2) - [Step 1. Installation](#step-1-installation-4) - [Step 2. Create keys and `deposit_data-*.json`](#step-2-create-keys-and-deposit_data-json-5) + - [Language Argument](#language-argument-3) - [Commands](#commands-4) - [Arguments](#arguments-4) - [Option 3. Build `deposit-cli` with `virtualenv`](#option-3-build-deposit-cli-with-virtualenv-1) - [Step 0. Python version checking](#step-0-python-version-checking-3) - [Step 1. Installation](#step-1-installation-5) - [Step 2. Create keys and `deposit_data-*.json`](#step-2-create-keys-and-deposit_data-json-6) + - [Language Argument](#language-argument-4) - [Commands](#commands-5) - [Arguments](#arguments-5) - [Development](#development) @@ -102,6 +108,14 @@ or run the following command to enter the interactive CLI and generate keys from ./deposit existing-mnemonic ``` +###### language Argument + +The Launchpad offers many language/internationalization options. If you wish to select one as a CLI argument, it must be passed in before one of the commands is chosen. + +| Argument | Type | Description | +| -------- | -------- | -------- | +| `--language` | String. Options: `العربية`, `ελληνικά`, `English`, `Français`, `Bahasa melayu`, `Italiano`, `日本語`, `한국어`, `Português do Brasil`, `român`, `简体中文`. Default to `English` | The language you wish to use the CLI in. | + ###### Commands The CLI offers different commands depending on what you want to do with the tool. @@ -118,7 +132,7 @@ You can use `new-mnemonic --help` to see all arguments. Note that if there are m | Argument | Type | Description | | -------- | -------- | -------- | | `--num_validators` | Non-negative integer | The number of signing keys you want to generate. Note that the child key(s) are generated via the same master key. | -| `--mnemonic_language` | String. Options: `chinese_simplified`, `chinese_traditional`, `czech`, `english`, `italian`, `korean`, `portuguese`, `spanish`. Default to `english` | The mnemonic language | +| `--mnemonic_language` | String. Options: `简体中文`, `繁體中文`, `český jazyk`, `English`, `Italiano`, `한국어`, `Português`, `Español`. Default to `English` | The mnemonic language | | `--folder` | String. Pointing to `./validator_keys` by default | The folder path for the keystore(s) and deposit(s) | | `--chain` | String. `mainnet` by default | The chain setting for the signing domain. | | `--eth1_withdrawal_address` | String. Eth1 address in hexadecimal encoded form | If this field is set and valid, the given Eth1 address will be used to create the withdrawal credentials. Otherwise, it will generate withdrawal credentials with the mnemonic-derived withdrawal public key in [EIP-2334 format](https://eips.ethereum.org/EIPS/eip-2334#eth2-specific-parameters). | @@ -199,6 +213,9 @@ You can also run the tool with optional arguments: ./deposit.sh existing-mnemonic --num_validators= --validator_start_index= --chain= --folder= ``` +###### Language Argument + +See [here](#language_argument) for `--language` arguments. ###### Commands See [here](#commands) @@ -262,6 +279,10 @@ python3 ./eth2deposit/deposit.py new-mnemonic --num_validators= python3 ./eth2deposit/deposit.py existing-mnemonic --num_validators= --validator_start_index= --chain= --folder= ``` +###### Language Argument + +See [here](#language_argument) for `--language` arguments. + ###### Commands See [here](#commands) @@ -341,6 +362,10 @@ deposit.exe new-mnemonic --num_validators= --mnemonic_language=e deposit.exe existing-mnemonic --num_validators= --validator_start_index= --chain= --folder= ``` +###### Language Argument + +See [here](#language_argument) for `--language` arguments. + ###### Commands See [here](#commands) @@ -399,6 +424,10 @@ You can also run the tool with optional arguments: ./deposit.sh existing-mnemonic --num_validators= --validator_start_index= --chain= --folder= ``` +###### Language Argument + +See [here](#language_argument) for `--language` arguments. + ###### Commands See [here](#commands) @@ -459,6 +488,10 @@ python .\eth2deposit\deposit.py new-mnemonic --num_validators= - python .\eth2deposit\deposit.pyexisting-mnemonic --num_validators= --validator_start_index= --chain= --folder= ``` +###### Language Argument + +See [here](#language_argument) for `--language` arguments. + ###### Commands See [here](#commands) diff --git a/build_configs/linux/build.spec b/build_configs/linux/build.spec index aff6396f..824a8960 100644 --- a/build_configs/linux/build.spec +++ b/build_configs/linux/build.spec @@ -5,11 +5,14 @@ block_cipher = None a = Analysis(['../../eth2deposit/deposit.py'], binaries=[], - datas=[('../../eth2deposit/key_handling/key_derivation/word_lists/*.txt', './eth2deposit/key_handling/key_derivation/word_lists/')], + datas=[ + ('../../eth2deposit/key_handling/key_derivation/word_lists/*.txt', './eth2deposit/key_handling/key_derivation/word_lists/'), + ('../../eth2deposit/intl', './eth2deposit/intl',) + ], hiddenimports=[], hookspath=[], runtime_hooks=[], - excludes=[], + excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, diff --git a/build_configs/linux/requirements.txt b/build_configs/linux/requirements.txt index d00dd0d3..b38e4c52 100644 --- a/build_configs/linux/requirements.txt +++ b/build_configs/linux/requirements.txt @@ -2,8 +2,8 @@ -r ../../requirements.txt # Build tools for binary distribution -PyInstaller==3.6 \ - --hash=sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7 +pyinstaller==4.2 \ + --hash=sha256:f5c0eeb2aa663cce9a5404292c0195011fa500a6501c873a466b2e8cad3c950c setuptools==49.2.0 \ --hash=sha256:272c7f48f5cddc5af5901f4265274c421c7eede5c8bc454ac2903d3f8fc365e9 \ --hash=sha256:afe9e81fee0270d3f60d52608549cc8ec4c46dada8c95640c1a00160f577acf2 @@ -45,3 +45,16 @@ altgraph==0.17 \ macholib==1.14 \ --hash=sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432 \ --hash=sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281 +pyinstaller-hooks-contrib==2021.1 \ + --hash=sha256:27558072021857d89524c42136feaa2ffe4f003f1bdf0278f9b24f6902c1759c \ + --hash=sha256:892310e6363655838485ee748bf1c5e5cade7963686d9af8650ee218a3e0b031 +importlib-metadata==3.10.0 \ + --hash=sha256:c9db46394197244adf2f0b08ec5bc3cf16757e9590b02af1fca085c16c0d600a \ + --hash=sha256:d2d46ef77ffc85cbf7dac7e81dd663fde71c45326131bea8033b9bad42268ebe +zipp==3.4.1 \ + --hash=sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76 \ + --hash=sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098 +typing-extensions==3.7.4.3 \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f diff --git a/build_configs/macos/build.spec b/build_configs/macos/build.spec index bd82fe84..ddc3fd37 100644 --- a/build_configs/macos/build.spec +++ b/build_configs/macos/build.spec @@ -4,12 +4,15 @@ block_cipher = None a = Analysis(['../../eth2deposit/deposit.py'], - binaries=[('/System/Library/Frameworks/Tk.framework/Tk', 'tk'), ('/System/Library/Frameworks/Tcl.framework/Tcl', 'tcl')], - datas=[('../../eth2deposit/key_handling/key_derivation/word_lists/*.txt', './eth2deposit/key_handling/key_derivation/word_lists/')], + binaries=None, + datas=[ + ('../../eth2deposit/key_handling/key_derivation/word_lists/*.txt', './eth2deposit/key_handling/key_derivation/word_lists/'), + ('../../eth2deposit/intl', './eth2deposit/intl',) + ], hiddenimports=[], hookspath=[], runtime_hooks=[], - excludes=[], + excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, diff --git a/build_configs/macos/requirements.txt b/build_configs/macos/requirements.txt index d00dd0d3..b38e4c52 100644 --- a/build_configs/macos/requirements.txt +++ b/build_configs/macos/requirements.txt @@ -2,8 +2,8 @@ -r ../../requirements.txt # Build tools for binary distribution -PyInstaller==3.6 \ - --hash=sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7 +pyinstaller==4.2 \ + --hash=sha256:f5c0eeb2aa663cce9a5404292c0195011fa500a6501c873a466b2e8cad3c950c setuptools==49.2.0 \ --hash=sha256:272c7f48f5cddc5af5901f4265274c421c7eede5c8bc454ac2903d3f8fc365e9 \ --hash=sha256:afe9e81fee0270d3f60d52608549cc8ec4c46dada8c95640c1a00160f577acf2 @@ -45,3 +45,16 @@ altgraph==0.17 \ macholib==1.14 \ --hash=sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432 \ --hash=sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281 +pyinstaller-hooks-contrib==2021.1 \ + --hash=sha256:27558072021857d89524c42136feaa2ffe4f003f1bdf0278f9b24f6902c1759c \ + --hash=sha256:892310e6363655838485ee748bf1c5e5cade7963686d9af8650ee218a3e0b031 +importlib-metadata==3.10.0 \ + --hash=sha256:c9db46394197244adf2f0b08ec5bc3cf16757e9590b02af1fca085c16c0d600a \ + --hash=sha256:d2d46ef77ffc85cbf7dac7e81dd663fde71c45326131bea8033b9bad42268ebe +zipp==3.4.1 \ + --hash=sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76 \ + --hash=sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098 +typing-extensions==3.7.4.3 \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f diff --git a/build_configs/windows/build.spec b/build_configs/windows/build.spec index 48725a5a..2276beaf 100644 --- a/build_configs/windows/build.spec +++ b/build_configs/windows/build.spec @@ -5,11 +5,14 @@ block_cipher = None a = Analysis(['..\\..\\eth2deposit\\deposit.py'], binaries=[], - datas=[('..\\..\\eth2deposit\\key_handling\\key_derivation\\word_lists\\*.txt', '.\\eth2deposit\\key_handling\\key_derivation\\word_lists')], + datas=[ + ('..\\..\\eth2deposit\\key_handling\\key_derivation\\word_lists\\*.txt', '.\\eth2deposit\\key_handling\\key_derivation\\word_lists'), + ('..\\..\\eth2deposit\\intl', '.\\eth2deposit\\intl'), + ], hiddenimports=[], hookspath=[], runtime_hooks=[], - excludes=[], + excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, diff --git a/build_configs/windows/requirements.txt b/build_configs/windows/requirements.txt index c5528544..5dbb7605 100644 --- a/build_configs/windows/requirements.txt +++ b/build_configs/windows/requirements.txt @@ -2,8 +2,8 @@ -r ../../requirements.txt # Build tools for binary distribution -PyInstaller==3.6 \ - --hash=sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7 +pyinstaller==4.2 \ + --hash=sha256:f5c0eeb2aa663cce9a5404292c0195011fa500a6501c873a466b2e8cad3c950c setuptools==49.2.0 \ --hash=sha256:272c7f48f5cddc5af5901f4265274c421c7eede5c8bc454ac2903d3f8fc365e9 \ --hash=sha256:afe9e81fee0270d3f60d52608549cc8ec4c46dada8c95640c1a00160f577acf2 @@ -65,3 +65,16 @@ pywin32==228 \ pywin32-ctypes==0.2.0 \ --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98 \ --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 +pyinstaller-hooks-contrib==2021.1 \ + --hash=sha256:27558072021857d89524c42136feaa2ffe4f003f1bdf0278f9b24f6902c1759c \ + --hash=sha256:892310e6363655838485ee748bf1c5e5cade7963686d9af8650ee218a3e0b031 +importlib-metadata==3.10.0 \ + --hash=sha256:c9db46394197244adf2f0b08ec5bc3cf16757e9590b02af1fca085c16c0d600a \ + --hash=sha256:d2d46ef77ffc85cbf7dac7e81dd663fde71c45326131bea8033b9bad42268ebe +zipp==3.4.1 \ + --hash=sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76 \ + --hash=sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098 +typing-extensions==3.7.4.3 \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f diff --git a/eth2deposit/cli/existing_mnemonic.py b/eth2deposit/cli/existing_mnemonic.py index 2c0970c2..f0b2a1ae 100644 --- a/eth2deposit/cli/existing_mnemonic.py +++ b/eth2deposit/cli/existing_mnemonic.py @@ -10,61 +10,63 @@ from eth2deposit.utils.constants import ( WORD_LISTS_PATH, ) +from eth2deposit.utils.click import ( + captive_prompt_callback, + jit_option, +) +from eth2deposit.utils.intl import load_text +from eth2deposit.utils.validation import validate_int_range from .generate_keys import ( generate_keys, generate_keys_arguments_decorator, ) -def validate_mnemonic(cts: click.Context, param: Any, mnemonic: str) -> str: +def validate_mnemonic(ctx: click.Context, param: Any, mnemonic: str) -> str: if verify_mnemonic(mnemonic, WORD_LISTS_PATH): return mnemonic else: - raise ValidationError('That is not a valid mnemonic, please check for typos.') + raise ValidationError(load_text(['err_invalid_mnemonic'])) @click.command( - help='Generate (or recover) keys from an existing mnemonic', + help=load_text(['arg_existing_mnemonic', 'help'], func='existing_mnemonic'), ) -@click.pass_context -@click.option( - '--mnemonic', +@jit_option( callback=validate_mnemonic, - help=('The mnemonic that you used to generate your keys. (It is recommended not to use this argument, and wait for ' - 'the CLI to ask you for your mnemonic as otherwise it will appear in your shell history.)'), - prompt='Please enter your mnemonic separated by spaces (" ")', - required=True, + help=lambda: load_text(['arg_mnemonic', 'help'], func='existing_mnemonic'), + param_decls='--mnemonic', + prompt=lambda: load_text(['arg_mnemonic', 'prompt'], func='existing_mnemonic'), type=str, ) -@click.password_option( - '--mnemonic-password', +@jit_option( + callback=captive_prompt_callback( + lambda x: x, + lambda: load_text(['arg_mnemonic_password', 'prompt'], func='existing_mnemonic'), + lambda: load_text(['arg_mnemonic_password', 'confirm'], func='existing_mnemonic'), + lambda: load_text(['arg_mnemonic_password', 'mismatch'], func='existing_mnemonic'), + True, + ), default='', - help=('This is almost certainly not the argument you are looking for: it is for mnemonic passwords, not keystore ' - 'passwords. Providing a password here when you didn\'t use one initially, can result in lost keys (and ' - 'therefore funds)! Also note that if you used this tool to generate your mnemonic intially, then you did not ' - 'use a mnemonic password. However, if you are certain you used a password to "increase" the security of your ' - 'mnemonic, this is where you enter it.'), + help=lambda: load_text(['arg_mnemonic_password', 'help'], func='existing_mnemonic'), + hidden=True, + param_decls='--mnemonic-password', prompt=False, ) -@click.option( - '--validator_start_index', - confirmation_prompt=True, +@jit_option( + callback=captive_prompt_callback( + lambda num: validate_int_range(num, 0, 2**32), + lambda: load_text(['arg_validator_start_index', 'prompt'], func='existing_mnemonic'), + lambda: load_text(['arg_validator_start_index', 'confirm'], func='existing_mnemonic'), + ), default=0, - 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,'), - type=click.IntRange(0, 2**32 - 1), + help=lambda: load_text(['arg_validator_start_index', 'help'], func='existing_mnemonic'), + param_decls="--validator_start_index", + prompt=lambda: load_text(['arg_validator_start_index', 'prompt'], func='existing_mnemonic'), ) @generate_keys_arguments_decorator +@click.pass_context def existing_mnemonic(ctx: click.Context, mnemonic: str, mnemonic_password: str, **kwargs: Any) -> None: - if mnemonic_password != '': - click.clear() - click.confirm( - ('Are you absolutely certain that you used a mnemonic password? ' - '(This is different from a keystore password!) ' - 'Using one when you are not supposed to can result in loss of funds!'), - abort=True) - - ctx.obj = {'mnemonic': mnemonic, 'mnemonic_password': mnemonic_password} + ctx.obj = {} if ctx.obj is None else ctx.obj # Create a new ctx.obj if it doesn't exist + ctx.obj.update({'mnemonic': mnemonic, 'mnemonic_password': mnemonic_password}) ctx.forward(generate_keys) diff --git a/eth2deposit/cli/generate_keys.py b/eth2deposit/cli/generate_keys.py index 4c12c3d9..76a60811 100644 --- a/eth2deposit/cli/generate_keys.py +++ b/eth2deposit/cli/generate_keys.py @@ -14,6 +14,7 @@ from eth2deposit.exceptions import ValidationError from eth2deposit.utils.validation import ( verify_deposit_data_json, + validate_int_range, validate_password_strength, ) from eth2deposit.utils.constants import ( @@ -21,6 +22,15 @@ DEFAULT_VALIDATOR_KEYS_FOLDER_NAME, ) from eth2deposit.utils.ascii_art import RHINO_0 +from eth2deposit.utils.click import ( + captive_prompt_callback, + choice_prompt_func, + jit_option, +) +from eth2deposit.utils.intl import ( + closest_match, + load_text, +) from eth2deposit.settings import ( ALL_CHAINS, MAINNET, @@ -32,43 +42,14 @@ def get_password(text: str) -> str: return click.prompt(text, hide_input=True, show_default=False, type=str) -def validate_password(cts: click.Context, param: Any, password: str) -> str: - is_valid_password = False - - # The given password has passed confirmation - try: - validate_password_strength(password) - except ValidationError as e: - click.echo(f'Error: {e} Please retype.') - else: - is_valid_password = True - - while not is_valid_password: - password = get_password(text='Type the password that secures your validator keystore(s)') - try: - validate_password_strength(password) - except ValidationError as e: - click.echo(f'Error: {e} Please retype.') - else: - # Confirm password - password_confirmation = get_password(text='Repeat for confirmation') - if password == password_confirmation: - is_valid_password = True - else: - click.echo('Error: the two entered values do not match. Please retype again.') - - return password - - def validate_eth1_withdrawal_address(cts: click.Context, param: Any, address: str) -> HexAddress: if address is None: return None if not is_hex_address(address): - raise ValueError("The given Eth1 address is not in hexadecimal encoded form.") + raise ValueError(load_text(['err_invalid_ECDSA_hex_addr'])) normalized_address = to_normalized_address(address) - click.echo(f'\n**[Warning] you are setting Eth1 address {normalized_address} as your withdrawal address. ' - 'Please ensure that you have control over this address.**\n') + click.echo('\n%s\n' % load_text(['msg_ECDSA_addr_withdrawal'])) return normalized_address @@ -78,41 +59,55 @@ def generate_keys_arguments_decorator(function: Callable[..., Any]) -> Callable[ to obtain the necessary arguments for the generate_keys() subcommand. ''' decorators = [ - click.option( - '--num_validators', - prompt='Please choose how many validators you wish to run', - help='The number of validators keys you want to generate (you can always generate more later)', - required=True, - type=click.IntRange(0, 2**32 - 1), + jit_option( + callback=captive_prompt_callback( + lambda num: validate_int_range(num, 1, 2**32), + lambda: load_text(['num_validators', 'prompt'], func='generate_keys_arguments_decorator') + ), + help=lambda: load_text(['num_validators', 'help'], func='generate_keys_arguments_decorator'), + param_decls="--num_validators", + prompt=lambda: load_text(['num_validators', 'prompt'], func='generate_keys_arguments_decorator'), ), - click.option( - '--folder', + jit_option( default=os.getcwd(), - help='The folder to place the generated keystores and deposit_data.json in', + help=lambda: load_text(['folder', 'help'], func='generate_keys_arguments_decorator'), + param_decls='--folder', type=click.Path(exists=True, file_okay=False, dir_okay=True), ), - click.option( - '--chain', + jit_option( + callback=captive_prompt_callback( + lambda x: closest_match(x, list(ALL_CHAINS.keys())), + choice_prompt_func( + lambda: load_text(['chain', 'prompt'], func='generate_keys_arguments_decorator'), + list(ALL_CHAINS.keys()) + ), + ), default=MAINNET, - help='The version of eth2 you are targeting. use "mainnet" if you are depositing ETH', - prompt='Please choose the (mainnet or testnet) network/chain name', - type=click.Choice(ALL_CHAINS.keys(), case_sensitive=False), + help=lambda: load_text(['chain', 'help'], func='generate_keys_arguments_decorator'), + param_decls='--chain', + prompt=choice_prompt_func( + lambda: load_text(['chain', 'prompt'], func='generate_keys_arguments_decorator'), + list(ALL_CHAINS.keys()) + ), ), - click.password_option( - '--keystore_password', - callback=validate_password, - help=('The password that will secure your keystores. You will need to re-enter this to decrypt them when ' - 'you setup your eth2 validators. (It is reccomened not to use this argument, and wait for the CLI ' - 'to ask you for your mnemonic as otherwise it will appear in your shell history.)'), - prompt='Type the password that secures your validator keystore(s)', + jit_option( + callback=captive_prompt_callback( + validate_password_strength, + lambda:load_text(['keystore_password', 'prompt'], func='generate_keys_arguments_decorator'), + lambda:load_text(['keystore_password', 'confirm'], func='generate_keys_arguments_decorator'), + lambda: load_text(['keystore_password', 'mismatch'], func='generate_keys_arguments_decorator'), + True, + ), + help=lambda: load_text(['keystore_password', 'help'], func='generate_keys_arguments_decorator'), + hide_input=True, + param_decls='--keystore_password', + prompt=lambda: load_text(['keystore_password', 'prompt'], func='generate_keys_arguments_decorator'), ), - click.option( - '--eth1_withdrawal_address', - default=None, + jit_option( callback=validate_eth1_withdrawal_address, - help=('If this field is set and valid, the given Eth1 address will be used to create the ' - 'withdrawal credentials. Otherwise, it will generate withdrawal credentials with the ' - 'mnemonic-derived withdrawal public key.'), + default=None, + help=lambda: load_text(['eth1_withdrawal_address', 'help'], func='generate_keys_arguments_decorator'), + param_decls='--eth1_withdrawal_address', ), ] for decorator in reversed(decorators): @@ -134,7 +129,7 @@ def generate_keys(ctx: click.Context, validator_start_index: int, os.mkdir(folder) click.clear() click.echo(RHINO_0) - click.echo('Creating your keys.') + click.echo(load_text(['msg_key_creation'])) credentials = CredentialList.from_mnemonic( mnemonic=mnemonic, mnemonic_password=mnemonic_password, @@ -147,8 +142,8 @@ def generate_keys(ctx: click.Context, validator_start_index: int, keystore_filefolders = credentials.export_keystores(password=keystore_password, folder=folder) deposits_file = credentials.export_deposit_data_json(folder=folder) if not credentials.verify_keystores(keystore_filefolders=keystore_filefolders, password=keystore_password): - raise ValidationError("Failed to verify the keystores.") + raise ValidationError(load_text(['err_verify_keystores'])) if not verify_deposit_data_json(deposits_file, credentials.credentials): - raise ValidationError("Failed to verify the deposit data JSON files.") - click.echo('\nSuccess!\nYour keys can be found at: %s' % folder) - click.pause('\n\nPress any key.') + raise ValidationError(load_text(['err_verify_deposit'])) + click.echo(load_text(['msg_creation_success']) + folder) + click.pause(load_text(['msg_pause'])) diff --git a/eth2deposit/cli/new_mnemonic.py b/eth2deposit/cli/new_mnemonic.py index af278c6c..1bf27fba 100644 --- a/eth2deposit/cli/new_mnemonic.py +++ b/eth2deposit/cli/new_mnemonic.py @@ -4,29 +4,44 @@ ) from eth2deposit.key_handling.key_derivation.mnemonic import ( - get_languages, get_mnemonic, ) -from eth2deposit.utils.constants import WORD_LISTS_PATH +from eth2deposit.utils.click import ( + captive_prompt_callback, + choice_prompt_func, + jit_option, +) +from eth2deposit.utils.constants import ( + MNEMONIC_LANG_OPTIONS, + WORD_LISTS_PATH, +) +from eth2deposit.utils.intl import ( + fuzzy_reverse_dict_lookup, + load_text, + get_first_options, +) from .generate_keys import ( generate_keys, generate_keys_arguments_decorator, ) -languages = get_languages(WORD_LISTS_PATH) +languages = get_first_options(MNEMONIC_LANG_OPTIONS) @click.command( - help='Generate a new mnemonic and keys', + help=load_text(['arg_new_mnemonic', 'help'], func='new_mnemonic'), ) @click.pass_context -@click.option( - '--mnemonic_language', - default='english', - help='The language that your mnemonic is in.', - prompt='Please choose your mnemonic language', - type=click.Choice(languages, case_sensitive=False), +@jit_option( + callback=captive_prompt_callback( + lambda mnemonic_language: fuzzy_reverse_dict_lookup(mnemonic_language, MNEMONIC_LANG_OPTIONS), + choice_prompt_func(lambda: load_text(['arg_mnemonic_language', 'prompt'], func='new_mnemonic'), languages), + ), + default=lambda: load_text(['arg_mnemonic_language', 'default'], func='new_mnemonic'), + help=lambda: load_text(['arg_mnemonic_language', 'help'], func='new_mnemonic'), + param_decls='--mnemonic_language', + prompt=choice_prompt_func(lambda: load_text(['arg_mnemonic_language', 'prompt'], func='new_mnemonic'), languages), ) @generate_keys_arguments_decorator def new_mnemonic(ctx: click.Context, mnemonic_language: str, **kwargs: Any) -> None: @@ -34,12 +49,12 @@ def new_mnemonic(ctx: click.Context, mnemonic_language: str, **kwargs: Any) -> N test_mnemonic = '' while mnemonic != test_mnemonic: click.clear() - click.echo('This is your seed phrase. Write it down and store it safely, it is the ONLY way to retrieve your deposit.') # noqa: E501 + click.echo(load_text(['msg_mnemonic_presentation'])) click.echo('\n\n%s\n\n' % mnemonic) - click.pause('Press any key when you have written down your mnemonic.') + click.pause(load_text(['msg_press_any_key'])) click.clear() - test_mnemonic = click.prompt('Please type your mnemonic (separated by spaces) to confirm you have written it down\n\n') # noqa: E501 + test_mnemonic = click.prompt(load_text(['msg_mnemonic_retype_prompt']) + '\n\n') test_mnemonic = test_mnemonic.lower() click.clear() # Do NOT use mnemonic_password. diff --git a/eth2deposit/credentials.py b/eth2deposit/credentials.py index c76b26d0..c63af766 100644 --- a/eth2deposit/credentials.py +++ b/eth2deposit/credentials.py @@ -24,6 +24,7 @@ MIN_DEPOSIT_AMOUNT, ) from eth2deposit.utils.crypto import SHA256 +from eth2deposit.utils.intl import load_text from eth2deposit.utils.ssz import ( compute_deposit_domain, compute_signing_root, @@ -180,7 +181,7 @@ def from_mnemonic(cls, f"The number of keys ({num_keys}) doesn't equal to the corresponding deposit amounts ({len(amounts)})." ) key_indices = range(start_index, start_index + num_keys) - with click.progressbar(key_indices, label='Creating your keys:\t\t', + with click.progressbar(key_indices, label=load_text(['msg_key_creation']), show_percent=False, show_pos=True) as indices: return cls([Credential(mnemonic=mnemonic, mnemonic_password=mnemonic_password, index=index, amount=amounts[index - start_index], chain_setting=chain_setting, @@ -188,12 +189,12 @@ def from_mnemonic(cls, for index in indices]) def export_keystores(self, password: str, folder: str) -> List[str]: - with click.progressbar(self.credentials, label='Creating your keystores:\t', + with click.progressbar(self.credentials, label=load_text(['msg_keystore_creation']), show_percent=False, show_pos=True) as credentials: return [credential.save_signing_keystore(password=password, folder=folder) for credential in credentials] def export_deposit_data_json(self, folder: str) -> str: - with click.progressbar(self.credentials, label='Creating your depositdata:\t', + with click.progressbar(self.credentials, label=load_text(['msg_depositdata_creation']), show_percent=False, show_pos=True) as credentials: deposit_data = [cred.deposit_datum_dict for cred in credentials] filefolder = os.path.join(folder, 'deposit_data-%i.json' % time.time()) @@ -204,7 +205,8 @@ def export_deposit_data_json(self, folder: str) -> str: return filefolder def verify_keystores(self, keystore_filefolders: List[str], password: str) -> bool: - with click.progressbar(zip(self.credentials, keystore_filefolders), label='Verifying your keystores:\t', + with click.progressbar(zip(self.credentials, keystore_filefolders), + label=load_text(['msg_keystore_verification']), length=len(self.credentials), show_percent=False, show_pos=True) as items: return all(credential.verify_keystore(keystore_filefolder=filefolder, password=password) for credential, filefolder in items) diff --git a/eth2deposit/deposit.py b/eth2deposit/deposit.py index 0d2cd403..0056075e 100644 --- a/eth2deposit/deposit.py +++ b/eth2deposit/deposit.py @@ -1,8 +1,20 @@ -import sys import click +import sys from eth2deposit.cli.existing_mnemonic import existing_mnemonic from eth2deposit.cli.new_mnemonic import new_mnemonic +from eth2deposit.utils.click import ( + captive_prompt_callback, + choice_prompt_func, + jit_option, +) +from eth2deposit.utils import config +from eth2deposit.utils.constants import INTL_LANG_OPTIONS +from eth2deposit.utils.intl import ( + get_first_options, + fuzzy_reverse_dict_lookup, + load_text, +) def check_python_version() -> None: @@ -10,13 +22,33 @@ def check_python_version() -> None: Checks that the python version running is sufficient and exits if not. ''' if sys.version_info < (3, 7): - click.pause('Your python version is insufficient, please install version 3.7 or greater.') + click.pause(load_text(['err_python_version'])) sys.exit() @click.group() -def cli() -> None: - pass +@click.pass_context +@jit_option( + '--language', + callback=captive_prompt_callback( + lambda language: fuzzy_reverse_dict_lookup(language, INTL_LANG_OPTIONS), + choice_prompt_func(lambda: 'Please choose your language', get_first_options(INTL_LANG_OPTIONS)), + ), + default='English', + help='The language you wish to use the CLI in.', + prompt=choice_prompt_func(lambda: 'Please choose your language', get_first_options(INTL_LANG_OPTIONS))(), + type=str, +) +@click.option( + '--non_interactive', + default=False, + is_flag=True, + help='Disables interactive prompts.', + hidden=True, +) +def cli(ctx: click.Context, language: str, non_interactive: bool) -> None: + config.language = language + config.non_interactive = non_interactive # Remove interactive commands cli.add_command(existing_mnemonic) diff --git a/eth2deposit/intl/__init__.py b/eth2deposit/intl/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eth2deposit/intl/ar/cli/existing_mnemonic.json b/eth2deposit/intl/ar/cli/existing_mnemonic.json new file mode 100644 index 00000000..504e6514 --- /dev/null +++ b/eth2deposit/intl/ar/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "هذا ليس مساعد ذاكرة صالحا، يرجى التحقق من الأخطاء المطبعية." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "إنشاء (أو استرداد) مفاتيح من مساعد ذاكرة موجود" + }, + "arg_mnemonic": { + "help": "مساعد الذاكرة الذي استخدمته لتوليد مفاتيحك. (يوصى بعدم استخدام هذه الوسيطة، وانتظر حتى يطلب منك الـ CLI مساعد الذاكرة الخاص وإلا فإنها ستظهر في سجل الغلاف الخاص بك.)", + "prompt": "الرجاء إدخال مساعد الذاكرة الخاص بك مفصولة بمسافات (\" \")" + }, + "arg_mnemonic_password": { + "help": "من المؤكد تقريبًا أن هذه ليست الوسيطة التي تبحث عنها: فهي لكلمات مرور مساعد الذاكرة، وليس كلمات مرور متجر المفاتيح. وقد يؤدي توفير كلمة مرور هنا عند عدم استخدامك لواحدة في البداية إلى فقدان المفاتيح (وبالتالي الأموال)! لاحظ أيضًا أنه إذا كنت تستخدم هذه الأداة لتوليد مساعد الذاكرة في البداية، فإنك لم تستخدم كلمة مرور مساعد الذاكرة. ومع ذلك، إذا كنت متأكداً من أنك استخدمت كلمة مرور \"لزيادة\" أمان مساعدة الذاكرة الخاصة بك، فهذا هو المكان حيث أدخلتها.", + "confirm": "هل أنت متأكد تماما من أنك استخدمت كلمة مرور مساعد الذاكرة؟ (هذا مختلف عن كلمة مرور متجر المفاتيح!) من المفترض أن يؤدي استخدام واحدة عند عدم افتراض استخدامها إلى فقدان الأموال! كرر للتأكيد" + }, + "arg_validator_start_index": { + "help": "أدخل الفهرس (الرقم الرئيسي) الذي تريد بدء توليد المزيد من المفاتيح منه. على سبيل المثال، إذا قمت بتوليد 4 مفاتيح في الماضي، فإنك ستدخل 4 هنا.", + "prompt": "أدخل الفهرس (الرقم الرئيسي) الذي تريد بدء توليد المزيد من المفاتيح منه. على سبيل المثال، إذا قمت بتوليد 4 مفاتيح في الماضي، فإنك ستدخل 4 هنا.", + "confirm": "كرر للتأكيد" + } + } +} diff --git a/eth2deposit/intl/ar/cli/generate_keys.json b/eth2deposit/intl/ar/cli/generate_keys.json new file mode 100644 index 00000000..ff2f2740 --- /dev/null +++ b/eth2deposit/intl/ar/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "عدد مفاتيح المدققين التي تريد إنشاؤها (يمكنك دائمًا إنشاء المزيد في وقت لاحق)", + "prompt": "الرجاء اختيار عدد المدققين الذين ترغب في تشغيلهم" + }, + "chain": { + "help": "إصدار eth2 الذي تستهدفه. استخدم \"mainnet\" إذا كنت تودع ETH", + "prompt": "الرجاء اختيار اسم الشبكة/السلسلة (mainnet أو testnet)" + }, + "keystore_password": { + "help": "كلمة المرور التي ستؤمن متاجر المفاتيح الخاصة بك. وسوف تحتاج إلى إعادة إدخال هذا لفك تشفيرها عند إعداد مدققي eth2 الخاصي بك. (يوصى بعدم استخدام هذه الوسيطة، وانتظر حتى يطلب منك الـ CLI مساعد الذاكرة الخاص وإلا فإنها ستظهر في سجل الغلاف الخاص بك.)", + "prompt": "كلمة المرور التي سوف تؤمن متاجر المفاتيح الخاصة بك. سوف تحتاج إلى إعادة إدخال هذا لفك تشفيرها عند إعداد مدققي eth2 الخاصين بك.", + "confirm": "كرر للتأكيد", + "mismatch": "خطأ: القيمتان اللتان تم إدخالهما غير متطابقتين. الرجاء الكتابة مرة أخرى." + } + }, + "generate_keys": { + "msg_key_creation": "إنشاء مفاتيحك.", + "msg_creation_success": "\nنجحت!\nيمكن العثور على مفاتيحك في: ", + "msg_pause": "\n\nاضغط على أي مفتاح.", + "err_verify_keystores": "فشل التحقق من متاجر المفاتيح.", + "err_verify_deposit": "فشل التحقق من ملفات بيانات الإيداع JSON." + } +} diff --git a/eth2deposit/intl/ar/cli/new_mnemonic.json b/eth2deposit/intl/ar/cli/new_mnemonic.json new file mode 100644 index 00000000..cbdc8620 --- /dev/null +++ b/eth2deposit/intl/ar/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "إنشاء مساعد ذاكرة جديد ومفاتيح جديدة" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "اللغة التي يتكلمها مساعد الذاكرة الخاص بك", + "prompt": "الرجاء اختيار لغة مساعد الذاكرة الخاص بك" + }, + "msg_mnemonic_presentation": "هذا هو مساعد الذاكرة الخاصة بك (العبارة الأصلية). قم بكتابتها وتخزينها بأمان، وهي الطريقة الوحيدة لاسترداد وديعتك.", + "msg_press_any_key": "اضغط على أي مفتاح عندما تكون قد دونت مساعد الذاكرة الخاص بك.", + "msg_mnemonic_retype_prompt": "الرجاء كتابة مساعد الذاكرة الخاص بك (مفصولاً بمسافات) لتأكيد أنك دونته" + } +} diff --git a/eth2deposit/intl/ar/credentials.json b/eth2deposit/intl/ar/credentials.json new file mode 100644 index 00000000..05eeeee6 --- /dev/null +++ b/eth2deposit/intl/ar/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "إنشاء المفاتيح الخاصة بك:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "إنشاء متاجر المفاتيح الخاصة بك:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "إنشاء بيانات الإيداع الخاصة بك:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "التحقق من متاجر المفاتيح الخاصة بك:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ar/deposit.json b/eth2deposit/intl/ar/deposit.json new file mode 100644 index 00000000..cc30c9ff --- /dev/null +++ b/eth2deposit/intl/ar/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "إصدار بايثون الخاص بك غير كافٍ، يرجى تثبيت الإصدار 3.7 أو الأحدث." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ar/utils/validation.json b/eth2deposit/intl/ar/utils/validation.json new file mode 100644 index 00000000..45453753 --- /dev/null +++ b/eth2deposit/intl/ar/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "التحقق من الإيداعات الخاصة بك:\t" + }, + "validate_password_strength": { + "msg_password_length": "يجب أن يكون طول كلمة المرور 8 على الأقل. الرجاء إعادة الكتابة" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/el/cli/existing_mnemonic.json b/eth2deposit/intl/el/cli/existing_mnemonic.json new file mode 100644 index 00000000..75e816e7 --- /dev/null +++ b/eth2deposit/intl/el/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "Αυτό δεν είναι έγκυρο μνημονικό, παρακαλώ ελέγξτε για ορθογραφικά." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Δημιουργία (ή ανάκτηση) κλειδιών από υπάρχον μνημονικό" + }, + "arg_mnemonic": { + "help": "Το μνημονικό που χρησιμοποιήσατε για τη δημιουργία των κλειδιών σας. (Συνιστάται να μην χρησιμοποιήσετε αυτή την παράμετρο, και να περιμένετε το CLI να σας ζητήσει το μνημονικό σας, διαφορετικά θα εμφανιστεί στο ιστορικό κελύφους σας.)", + "prompt": "Παρακαλώ εισάγετε το μνημονικό σας διαχωρισμένο με κενά διαστήματα (\" \")" + }, + "arg_mnemonic_password": { + "help": "Είναι σχεδόν βέβαιο ότι αυτή δεν είναι η παράμετρος που ψάχνετε: είναι για κωδικούς πρόσβασης μνημονικού, όχι κωδικούς πρόσβασης χώρου αποθήκευσης κλειδιών. Η παροχή κωδικού πρόσβασης ενώ δεν χρησιμοποιήσατε έναν αρχικά, μπορεί να οδηγήσει σε χαμένα κλειδιά (και επομένως κεφάλαια)! Επίσης, σημειώστε ότι αν χρησιμοποιήσατε αυτό το εργαλείο για να δημιουργήσετε το μνημονικό σας σε πρώτη φάση, τότε δεν χρησιμοποιήσατε έναν κωδικό πρόσβασης μνημονικού. Ωστόσο, αν είστε σίγουροι ότι χρησιμοποιήσατε έναν κωδικό πρόσβασης για να \"αυξήσετε\" την ασφάλεια του μνημονικού σας, πρέπει να τον πληκτρολογήσετε εδώ.", + "confirm": "Είστε απολύτως βέβαιοι ότι χρησιμοποιήσατε έναν κωδικό πρόσβασης μνημονικού; (Είναι διαφορετικό από έναν κωδικό πρόσβασης χώρου αποθήκευσης κλειδιών! Χρησιμοποιώντας έναν, ενώ υποτίθεται ότι δεν πρέπει μπορεί να οδηγήσει σε απώλεια κεφαλαίων! Επανάληψη για επιβεβαίωση" + }, + "arg_validator_start_index": { + "help": "Εισάγετε το ευρετήριο (αριθμός κλειδιού) από το οποίο θέλετε να αρχίσετε να δημιουργείτε περισσότερα κλειδιά. Για παράδειγμα, αν έχετε δημιουργήσει 4 κλειδιά στο παρελθόν, θα εισάγετε 4 εδώ.", + "prompt": "Εισάγετε το ευρετήριο (αριθμός κλειδιού) από το οποίο θέλετε να αρχίσετε να δημιουργείτε περισσότερα κλειδιά. Για παράδειγμα, αν έχετε δημιουργήσει 4 κλειδιά στο παρελθόν, θα εισάγετε 4 εδώ.", + "confirm": "Επανάληψη για επιβεβαίωση" + } + } +} diff --git a/eth2deposit/intl/el/cli/generate_keys.json b/eth2deposit/intl/el/cli/generate_keys.json new file mode 100644 index 00000000..5fdd6262 --- /dev/null +++ b/eth2deposit/intl/el/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "Ο αριθμός των κλειδιών επαληθευτών που θέλετε να δημιουργήσετε (μπορείτε πάντα να δημιουργήσετε περισσότερα αργότερα)", + "prompt": "Παρακαλώ επιλέξτε πόσους επαληθευτές θέλετε να εκτελέσετε" + }, + "chain": { + "help": "Η έκδοση του eth2 στην οποία στοχεύετε. Χρησιμοποιήστε το \"mainnet\" αν κάνετε κατάθεση ETH", + "prompt": "Παρακαλώ επιλέξτε το όνομα δικτύου/αλυσίδας (κεντρικό δίκτυο ή δίκτυο δοκιμών)" + }, + "keystore_password": { + "help": "Ο κωδικός πρόσβασης που θα ασφαλίσει τον χώρο αποθήκευσης των κλειδιών σας. Θα πρέπει να το εισάγετε ξανά για να τα αποκρυπτογραφήσετε όταν ρυθμίσετε τους επαληθευτές eth2 σας. (Συνιστάται να μην χρησιμοποιήσετε αυτή την παράμετρο, και να περιμένετε το CLI να σας ρωτήσει για το μνημονικό σας, διαφορετικά θα εμφανιστεί στο ιστορικό κελύφους σας.)", + "prompt": "Ο κωδικός πρόσβασης που θα ασφαλίσει τους χώρους αποθήκευσης κλειδιών σας. Θα πρέπει να τον εισάγετε ξανά για να τον αποκρυπτογραφήσετε όταν ρυθμίσετε τους επαληθευτές eth2 σας.", + "confirm": "Επανάληψη για επιβεβαίωση", + "mismatch": "Σφάλμα: οι δύο εισαχθείσες τιμές δεν ταιριάζουν. Παρακαλώ πληκτρολογήστε ξανά." + } + }, + "generate_keys": { + "msg_key_creation": "Δημιουργώντας τα κλειδιά σας.", + "msg_creation_success": "\nΕπιτυχία!\nΤα κλειδιά σας μπορούν να βρεθούν στο: ", + "msg_pause": "\n\nΠιέστε οποιοδήποτε πλήκτρο.", + "err_verify_keystores": "Αποτυχία επαλήθευσης των χώρων αποθήκευσης των κλειδιών.", + "err_verify_deposit": "Αποτυχία επαλήθευσης των αρχείων JSON δεδομένων κατάθεσης." + } +} diff --git a/eth2deposit/intl/el/cli/new_mnemonic.json b/eth2deposit/intl/el/cli/new_mnemonic.json new file mode 100644 index 00000000..630f4b25 --- /dev/null +++ b/eth2deposit/intl/el/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Δημιουργία νέου μνημονικού και κλειδιών" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "Η γλώσσα του μνημονικού σας", + "prompt": "Επιλέξτε τη γλώσσα του μνημονικού σας" + }, + "msg_mnemonic_presentation": "Αυτό είναι το μνημονικό σας (σειρά λέξεων). Γράψτε την και αποθηκεύστε την με ασφάλεια, είναι ο ΜΟΝΟΣ τρόπος για να ανακτήσετε την κατάθεσή σας.", + "msg_press_any_key": "Πιέστε οποιοδήποτε πλήκτρο όταν έχετε καταγράψει το μνημονικό σας.", + "msg_mnemonic_retype_prompt": "Πληκτρολογήστε το μνημονικό σας (διαχωρισμένο με κενά) για να επιβεβαιώσετε ότι το έχετε καταγράψει" + } +} diff --git a/eth2deposit/intl/el/credentials.json b/eth2deposit/intl/el/credentials.json new file mode 100644 index 00000000..42414767 --- /dev/null +++ b/eth2deposit/intl/el/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Δημιουργώντας τα κλειδιά σας:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Δημιουργώντας τους χώρους αποθήκευσης των κλειδιών σας:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Δημιουργώντας τα δεδομένα κατάθεσής σας:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Δημιουργώντας τους χώρους αποθήκευσης των κλειδιών σας:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/el/deposit.json b/eth2deposit/intl/el/deposit.json new file mode 100644 index 00000000..32ebca25 --- /dev/null +++ b/eth2deposit/intl/el/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Η έκδοση python σας δεν είναι επαρκής, εγκαταστήστε την έκδοση 3.7 ή μεγαλύτερη." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/el/utils/validation.json b/eth2deposit/intl/el/utils/validation.json new file mode 100644 index 00000000..cf1cb3de --- /dev/null +++ b/eth2deposit/intl/el/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Επαλήθευση των καταθέσεών σας:\t" + }, + "validate_password_strength": { + "msg_password_length": "Το μήκος του κωδικού πρόσβασης πρέπει να είναι τουλάχιστον 8. Πληκτρολογήστε ξανά" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/en/cli/existing_mnemonic.json b/eth2deposit/intl/en/cli/existing_mnemonic.json new file mode 100644 index 00000000..9b70c276 --- /dev/null +++ b/eth2deposit/intl/en/cli/existing_mnemonic.json @@ -0,0 +1,25 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "That is not a valid mnemonic, please check for typos." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Generate (or recover) keys from an existing mnemonic" + }, + "arg_mnemonic": { + "help": "The mnemonic that you used to generate your keys. (It is recommended not to use this argument, and wait for the CLI to ask you for your mnemonic as otherwise it will appear in your shell history.)", + "prompt": "Please enter your mnemonic separated by spaces (\" \")" + }, + "arg_mnemonic_password": { + "help": "This is almost certainly not the argument you are looking for: it is for mnemonic passwords, not keystore passwords. Providing a password here when you didn't use one initially, can result in lost keys (and therefore funds)! Also note that if you used this tool to generate your mnemonic initially, then you did not use a mnemonic password. However, if you are certain you used a password to \"increase\" the security of your mnemonic, this is where you enter it.", + "prompt": "Enter your mnemonic password (if you used one). Make sure you won't forget it, it can not be recovered.", + "confirm": "Repeat your mnemonic password for confirmation. Providing a password here when you didn't use one initially, can result in lost keys (and therefore funds)! Also note that if you used this tool to generate your mnemonic initially, then you did not use a mnemonic password. However, if you are certain you used a password to \"increase\" the security of your mnemonic, this is where you enter it.", + "mismatch": "The mnemonic password you entered doesn't match, please try again." + }, + "arg_validator_start_index": { + "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 index to confirm" + } + } +} diff --git a/eth2deposit/intl/en/cli/generate_keys.json b/eth2deposit/intl/en/cli/generate_keys.json new file mode 100644 index 00000000..4e71d3aa --- /dev/null +++ b/eth2deposit/intl/en/cli/generate_keys.json @@ -0,0 +1,35 @@ +{ + "validate_eth1_withdrawal_address": { + "err_invalid_ECDSA_hex_addr": "The given Eth1 address is not in hexadecimal encoded form.", + "msg_ECDSA_addr_withdrawal": "**[Warning] you are setting an Eth1 address as your withdrawal address. Please ensure that you have control over this address.**" + }, + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "The number of validators keys you want to generate (you can always generate more later)", + "prompt": "Please choose how many validators you wish to run" + }, + "folder": { + "help": "The folder path for the keystore(s) and deposit(s). Pointing to `./validator_keys` by default." + }, + "chain": { + "help": "The version of eth2 you are targeting. Use \"mainnet\" if you are depositing ETH", + "prompt": "Please choose the (mainnet or testnet) network/chain name" + }, + "keystore_password": { + "help": "The password that will secure your keystores. You will need to re-enter this to decrypt them when you setup your eth2 validators. (It is recommended not to use this argument, and wait for the CLI to ask you for your mnemonic as otherwise it will appear in your shell history.)", + "prompt": "Create a password that secures your validator keystore(s). You will need to re-enter this to decrypt them when you setup your eth2 validators.", + "confirm": "Repeat your keystore password for confirmation", + "mismatch": "Error: the two entered values do not match. Please type again." + }, + "eth1_withdrawal_address": { + "help": "If this field is set and valid, the given Eth1 address will be used to create the withdrawal credentials. Otherwise, it will generate withdrawal credentials with the mnemonic-derived withdrawal public key." + } + }, + "generate_keys": { + "msg_key_creation": "Creating your keys.", + "msg_creation_success": "\nSuccess!\nYour keys can be found at: ", + "msg_pause": "\n\nPress any key.", + "err_verify_keystores": "Failed to verify the keystores.", + "err_verify_deposit": "Failed to verify the deposit data JSON files." + } +} diff --git a/eth2deposit/intl/en/cli/new_mnemonic.json b/eth2deposit/intl/en/cli/new_mnemonic.json new file mode 100644 index 00000000..2c6d54c3 --- /dev/null +++ b/eth2deposit/intl/en/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Generate a new mnemonic and keys" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "The language that your mnemonic is in", + "prompt": "Please choose your mnemonic language" + }, + "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" + } +} diff --git a/eth2deposit/intl/en/credentials.json b/eth2deposit/intl/en/credentials.json new file mode 100644 index 00000000..da6f6559 --- /dev/null +++ b/eth2deposit/intl/en/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Creating your keys:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Creating your keystores:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Creating your depositdata:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Verifying your keystores:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/en/deposit.json b/eth2deposit/intl/en/deposit.json new file mode 100644 index 00000000..39755c08 --- /dev/null +++ b/eth2deposit/intl/en/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Your python version is insufficient, please install version 3.7 or greater." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/en/utils/validation.json b/eth2deposit/intl/en/utils/validation.json new file mode 100644 index 00000000..50145b22 --- /dev/null +++ b/eth2deposit/intl/en/utils/validation.json @@ -0,0 +1,14 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Verifying your deposits:\t" + }, + "validate_password_strength": { + "msg_password_length": "The password length should be at least 8. Please retype" + }, + "validate_int_range": { + "err_not_positive_integer": "That is not a positive integer. Please retype." + }, + "validate_choice": { + "err_invalid_choice": "That is not one of the valid choices. Please retype your choice." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/fr/cli/existing_mnemonic.json b/eth2deposit/intl/fr/cli/existing_mnemonic.json new file mode 100644 index 00000000..0375f61d --- /dev/null +++ b/eth2deposit/intl/fr/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "Ceci n'est pas une phrase mnémonique valide, veuillez vérifier s'il existe des fautes de frappe." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Générer (ou récupérer) des clés à partir d'une phrase mnémonique existante" + }, + "arg_mnemonic": { + "help": "Phrase mnémonique que vous avez utilisée pour générer vos clés. (Il est recommandé de ne pas utiliser ce argument, et d'attendre que l'ILC vous demande votre élément mnémonique, sinon il apparaîtra dans l'historique de votre interpréteur.)", + "prompt": "Veuillez saisir votre phrase mnémonique en séparant les mots par des espaces (\" \")" + }, + "arg_mnemonic_password": { + "help": "Ce n'est certainement pas l'argument que vous recherchez : il est destiné aux mots de passe mnémoniques, pas aux mots de passe de keystores. Fournir un mot de passe ici sans en avoir un utilisé initialement peut entraîner la perte de clés (et donc de fonds) ! Notez également que si vous avez utilisé cet outil pour générer votre phrase mnémonique initialement, cela signifie que vous n'avez pas utilisé de mot de passe mnémonique. Cependant, si vous êtes certain d'avoir utilisé un mot de passe pour \"augmenter\" la sécurité de votre phrase mnémonique, c'est ici que vous devez le saisir.", + "confirm": "Êtes-vous absolument certain d'avoir utilisé un mot de passe mnémonique ? (Différent d'un mot de passe de keystore !) Si vous en utilisez un sans être censé le faire, cela peut entraîner une perte de fonds ! Veuillez confirmer le mot de passe." + }, + "arg_validator_start_index": { + "help": "Saisissez l'index (numéro de clé) à partir duquel vous souhaitez commencer à générer d'autres clés. Par exemple, si vous avez généré 4 clés dans le passé, entrez 4.", + "prompt": "Saisissez l'index (numéro de clé) à partir duquel vous souhaitez commencer à générer d'autres clés. Par exemple, si vous avez généré 4 clés dans le passé, entrez 4.", + "confirm": "Veuillez confirmer le mot de passe." + } + } +} diff --git a/eth2deposit/intl/fr/cli/generate_keys.json b/eth2deposit/intl/fr/cli/generate_keys.json new file mode 100644 index 00000000..ec328c80 --- /dev/null +++ b/eth2deposit/intl/fr/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "Nombre de clés de validateurs que vous souhaitez générer (vous pourrez en générer davantage plus tard)", + "prompt": "Veuillez choisir le nombre de validateurs que vous souhaitez exécuter" + }, + "chain": { + "help": "Version d'Eth2 que vous ciblez. Utilisez \"mainnet\" si vous déposez de l'ETH.", + "prompt": "Veuillez choisir un nom de chaîne/réseau : mainnet (réseau principal) ou testnet (réseau de test)." + }, + "keystore_password": { + "help": "Mot de passe qui sécurisera vos keystores. Vous devrez le saisir de nouveau pour les décrypter quand vous configurerez vos validateurs Eth2. (Il est recommandé de ne pas utiliser ce argument et d'attendre que l'ILC vous demande votre phrase mnémonique, sinon il apparaîtra dans l'historique de votre interpréteur.)", + "prompt": "Mot de passe qui sécurisera vos keystores. Vous devrez le saisir de nouveau pour les décrypter quand vous configurerez vos validateurs Eth2.", + "confirm": "Veuillez confirmer le mot de passe.", + "mismatch": "Erreur : Les deux valeurs saisies ne correspondent pas. Veuillez réessayer." + } + }, + "generate_keys": { + "msg_key_creation": "Création de vos clés.", + "msg_creation_success": "\nOpération terminée !\nVos clés sont disponibles ici : ", + "msg_pause": "\n\nAppuyez sur n'importe quelle touche.", + "err_verify_keystores": "Impossible de vérifier les keystores.", + "err_verify_deposit": "Impossible de vérifier les fichiers JSON des données de dépôt." + } +} diff --git a/eth2deposit/intl/fr/cli/new_mnemonic.json b/eth2deposit/intl/fr/cli/new_mnemonic.json new file mode 100644 index 00000000..17ddc1bd --- /dev/null +++ b/eth2deposit/intl/fr/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Générer un nouvel élément mnémonique et des clés" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "Langue de votre phrase mnémonique", + "prompt": "Veuillez choisir la langue de votre phrase mnémonique." + }, + "msg_mnemonic_presentation": "Ceci est votre phrase mnémonique (seed). Notez-la et conservez-la en sécurité. Elle constitue le SEUL moyen de récupérer votre dépôt.", + "msg_press_any_key": "Une fois que vous avez écrit votre phrase mnémonique, appuyez sur n'importe quelle touche.", + "msg_mnemonic_retype_prompt": "Veuillez saisir votre phrase mnémonique (avec les mots séparés par des espaces) pour confirmer que vous l'avez écrite." + } +} diff --git a/eth2deposit/intl/fr/credentials.json b/eth2deposit/intl/fr/credentials.json new file mode 100644 index 00000000..86c70efb --- /dev/null +++ b/eth2deposit/intl/fr/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Création de vos clés :\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Création de vos keystores :\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Création de vos données de dépôt :\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Vérification de vos keystores :\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/fr/deposit.json b/eth2deposit/intl/fr/deposit.json new file mode 100644 index 00000000..24220bdc --- /dev/null +++ b/eth2deposit/intl/fr/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Votre version de Python est insuffisante. Veuillez installer la version 3.7 ou supérieure." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/fr/utils/validation.json b/eth2deposit/intl/fr/utils/validation.json new file mode 100644 index 00000000..7a76e7bb --- /dev/null +++ b/eth2deposit/intl/fr/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Vérification de vos dépôts :\t" + }, + "validate_password_strength": { + "msg_password_length": "Le mot de passe doit comporter au moins 8 caractères. Veuillez recommencer." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/id/cli/existing_mnemonic.json b/eth2deposit/intl/id/cli/existing_mnemonic.json new file mode 100644 index 00000000..b03a2a9c --- /dev/null +++ b/eth2deposit/intl/id/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "Bukan mnemonik yang valid, harap pastikan tidak ada kesalahan ketik." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Buat (atau pulihkan) kunci dari mnemonik yang sudah ada" + }, + "arg_mnemonic": { + "help": "Mnemonik yang Anda gunakan untuk membuat kunci Anda. (Disarankan tidak menggunakan argumen ini, dan menunggu CLI menanyakan mnemonik Anda supaya tidak akan muncul di riwayat shell Anda.)", + "prompt": "Silakan masukkan mnemonik Anda dipisahkan dengan spasi (\" \")" + }, + "arg_mnemonic_password": { + "help": "Ini kemungkinan bukan argumen yang Anda cari: ini untuk kata sandi mnemonik, bukan kata sandi keystore. Memasukkan kata sandi di sini ketika pada awalnya Anda tidak menggunakannya, dapat mengakibatkan kunci hilang (dan karenanya dana pun hilang)! Perhatikan juga bahwa jika Anda menggunakan alat ini untuk membuat mnemonik Anda pada awalnya, maka Anda tidak menggunakan kata sandi mnemonik. Namun, jika yakin Anda menggunakan kata sandi untuk \"meningkatkan\" keamanan mnemonik Anda, di sinilah Anda memasukkannya.", + "confirm": "Apakah Anda benar-benar yakin bahwa Anda menggunakan kata sandi mnemonik? (Ini berbeda dari kata sandi keystore!) Menggunakan kata sandi saat Anda tidak seharusnya melakukannya dapat mengakibatkan hilangnya dana! Ulangi untuk konfirmasi" + }, + "arg_validator_start_index": { + "help": "Masukkan indeks (nomor kunci) yang Anda inginkan untuk mulai membuat lebih banyak kunci. Misalnya, jika Anda pernah membuat 4 kunci sebelumnya, masukkan 4 di sini.", + "prompt": "Masukkan indeks (nomor kunci) yang Anda inginkan untuk mulai membuat lebih banyak kunci. Misalnya, jika Anda pernah membuat 4 kunci sebelumnya, masukkan 4 di sini.", + "confirm": "Ulangi untuk konfirmasi" + } + } +} diff --git a/eth2deposit/intl/id/cli/generate_keys.json b/eth2deposit/intl/id/cli/generate_keys.json new file mode 100644 index 00000000..de3d6af2 --- /dev/null +++ b/eth2deposit/intl/id/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "Jumlah kunci validator yang ingin Anda buat (Anda selalu dapat menghasilkan lebih banyak lagi nanti)", + "prompt": "Silakan pilih berapa banyak validator yang ingin Anda jalankan" + }, + "chain": { + "help": "Versi eth2 yang Anda targetkan. Gunakan \"mainnet\" jika Anda menyetorkan ETH", + "prompt": "Pilih nama jaringan / rantai (mainnet atau testnet)" + }, + "keystore_password": { + "help": "Kata sandi yang akan mengamankan keystore Anda. Anda perlu memasukkan ulang ini untuk mendekripsinya ketika Anda mengatur validator eth2 Anda. (Disarankan untuk tidak menggunakan argumen ini, dan tunggu CLI menanyakan mnemonik Anda supaya tidak akan muncul dalam riwayat shell Anda.)", + "prompt": "Kata sandi yang akan mengamankan keystore Anda. Anda perlu memasukkan ulang ini untuk mendekripsinya ketika Anda mengatur validator eth2 Anda.", + "confirm": "Ulangi untuk konfirmasi", + "mismatch": "Kesalahan: dua nilai yang dimasukkan tidak cocok. Silakan ketik ulang." + } + }, + "generate_keys": { + "msg_key_creation": "Membuat kunci Anda.", + "msg_creation_success": "\nSukses!\nKunci Anda dapat ditemukan di: ", + "msg_pause": "\n\nTekan tombol apa saja.", + "err_verify_keystores": "Gagal memverifikasi keystore.", + "err_verify_deposit": "Gagal memverifikasi data setoran file JSON." + } +} diff --git a/eth2deposit/intl/id/cli/new_mnemonic.json b/eth2deposit/intl/id/cli/new_mnemonic.json new file mode 100644 index 00000000..4e2b79e7 --- /dev/null +++ b/eth2deposit/intl/id/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Buat mnemonik dan kunci baru" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "Bahasa mnemonik Anda", + "prompt": "Silakan pilih bahasa mnemonik Anda" + }, + "msg_mnemonic_presentation": "Ini adalah mnemonik Anda (frasa benih). Catat dan simpan dengan aman, ini adalah SATU-SATUNYA cara untuk mengambil deposit Anda.", + "msg_press_any_key": "Tekan sembarang tombol setelah Anda menuliskan mnemonik Anda.", + "msg_mnemonic_retype_prompt": "Harap ketik mnemonik Anda (dipisahkan dengan spasi) untuk mengonfirmasi bahwa Anda telah menuliskannya" + } +} diff --git a/eth2deposit/intl/id/credentials.json b/eth2deposit/intl/id/credentials.json new file mode 100644 index 00000000..5c0fce35 --- /dev/null +++ b/eth2deposit/intl/id/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Membuat kunci Anda:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Membuat keystore Anda:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Membuat depositdata Anda:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Memverifikasi keystore Anda:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/id/deposit.json b/eth2deposit/intl/id/deposit.json new file mode 100644 index 00000000..9f4979d2 --- /dev/null +++ b/eth2deposit/intl/id/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Versi python Anda tidak cukup, harap instal versi 3.7 atau yang lebih baru." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/id/utils/validation.json b/eth2deposit/intl/id/utils/validation.json new file mode 100644 index 00000000..f2de64f8 --- /dev/null +++ b/eth2deposit/intl/id/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Memverifikasi deposit Anda:\t" + }, + "validate_password_strength": { + "msg_password_length": "Panjang kata sandi minimal harus 8. Harap ketik ulang" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/it/cli/existing_mnemonic.json b/eth2deposit/intl/it/cli/existing_mnemonic.json new file mode 100644 index 00000000..b27a1752 --- /dev/null +++ b/eth2deposit/intl/it/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "Questo non è un mnemonico valido. Controlla che la grafia sia corretta." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Genera (o recupera) chiavi da un mnemonico esistente" + }, + "arg_mnemonic": { + "help": "Il mnemonico che hai usato per generare le chiavi (è consigliabile non utilizzare questo argomento e attendere che il CLI chieda il mnemonico, altrimenti apparirà nella cronologia della shell).", + "prompt": "Inserisci il mnemonico separato da spazi (\" \")" + }, + "arg_mnemonic_password": { + "help": "Quasi sicuramente questo non è l'argomento che stai cercando: è per le password mnemoniche, non per le password dell'archivio chiavi. Fornire una password qui se non ne hai utilizzata una inizialmente può causare la perdita di chiavi (e quindi fondi)! Tieni presente inoltre che se hai usato questo strumento per generare il tuo mnemonico inizialmente, significa che non hai usato una password mnemonica. Se invece hai la certezza di aver usato una password per \"aumentare\" la sicurezza del tuo mnemonico, inseriscila qui.", + "confirm": "Hai la certezza assoluta di aver usato una password mnemonica? È diversa da una password dell'archivio chiavi. Se non devi utilizzarne una ma lo fai, potresti perdere fondi! Ripeti per conferma" + }, + "arg_validator_start_index": { + "help": "Inserisci l'indice (numero di chiave) da cui desideri iniziare a generare ulteriori chiavi. Ad esempio, se hai generato 4 chiavi in passato, inserisci 4.", + "prompt": "Inserisci l'indice (numero di chiave) da cui desideri iniziare a generare ulteriori chiavi. Ad esempio, se hai generato 4 chiavi in passato, inserisci 4.", + "confirm": "Ripeti per conferma" + } + } +} diff --git a/eth2deposit/intl/it/cli/generate_keys.json b/eth2deposit/intl/it/cli/generate_keys.json new file mode 100644 index 00000000..d21fff69 --- /dev/null +++ b/eth2deposit/intl/it/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "Il numero di chiavi di validatori che si desidera generare (è sempre possibile generarne altre in seguito)", + "prompt": "Scegli quanti validatori vuoi eseguire" + }, + "chain": { + "help": "La versione di eth2 desiderata. Utilizzare \"mainnet\" se depositano ETH", + "prompt": "Scegli il nome delle rete/catena (rete principale o di test)" + }, + "keystore_password": { + "help": "La password che proteggerà gli archivi chiavi. Dovrà essere inserita per decrittografare le chiavi durante la configurazione dei validatori eth2 (è consigliabile non utilizzare questo argomento e attendere che il CLI chieda il mnemonico, altrimenti apparirà nella cronologia della shell).", + "prompt": "La password che proteggerà gli archivi chiavi. Dovrai inserirla nuovamente per decrittografare gli archivi quando configurerai i tuoi validatori eth2.", + "confirm": "Ripeti per conferma", + "mismatch": "Errore: i due valori inseriti non corrispondono. Ripeti l'inserimento." + } + }, + "generate_keys": { + "msg_key_creation": "Creazione delle tue chiavi.", + "msg_creation_success": "\nOperazione riuscita.\nLe tue chiavi si trovano in: ", + "msg_pause": "\n\nPremi qualunque tasto.", + "err_verify_keystores": "Verifica degli archivi chiavi non riuscita.", + "err_verify_deposit": "Verifica dei file JSON dei dati di deposito non riuscita." + } +} diff --git a/eth2deposit/intl/it/cli/new_mnemonic.json b/eth2deposit/intl/it/cli/new_mnemonic.json new file mode 100644 index 00000000..bc528710 --- /dev/null +++ b/eth2deposit/intl/it/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Genera un nuovo mnemonico e chiavi" + }, + "arg_mnemonic_language": { + "default": "Italiano", + "help": "La lingua del mnemonico", + "prompt": "Scegli la lingua del mnemonico" + }, + "msg_mnemonic_presentation": "Questo è il tuo mnemonico (seed phrase). Prendi nota e tienilo in un luogo sicuro. Rappresenta l'UNICO modo per recuperare il tuo deposito.", + "msg_press_any_key": "Dopo aver preso nota del mnemonico, premi qualsiasi tasto.", + "msg_mnemonic_retype_prompt": "Digita il tuo mnemonico (separato da spazi) per confermare di averlo scritto." + } +} diff --git a/eth2deposit/intl/it/credentials.json b/eth2deposit/intl/it/credentials.json new file mode 100644 index 00000000..ccefe007 --- /dev/null +++ b/eth2deposit/intl/it/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Creazione delle tue chiavi:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Creazione dei tuoi archivi chiavi:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Creazione dei tuoi dati di deposito:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Verifica dei tuoi archivi chiavi:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/it/deposit.json b/eth2deposit/intl/it/deposit.json new file mode 100644 index 00000000..c892d630 --- /dev/null +++ b/eth2deposit/intl/it/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "La tua versione di python non è sufficiente, installa la versione 3.7 o superiore." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/it/utils/validation.json b/eth2deposit/intl/it/utils/validation.json new file mode 100644 index 00000000..ec270c20 --- /dev/null +++ b/eth2deposit/intl/it/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Verifica dei tuoi depositi:\t" + }, + "validate_password_strength": { + "msg_password_length": "La lunghezza della password deve essere almeno di 8 caratteri. Ripetila" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ja/cli/existing_mnemonic.json b/eth2deposit/intl/ja/cli/existing_mnemonic.json new file mode 100644 index 00000000..ddb20548 --- /dev/null +++ b/eth2deposit/intl/ja/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "有効なニーモニックではありません。誤字を確認してください。" + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "既存のニーモニックからキーを生成(または回復)" + }, + "arg_mnemonic": { + "help": "キーを生成するために使用したニーモニック。 (この引数を使用せずに、CLIからニーモニックの入力が求められるのを待つことを推奨します。そうしないとこれがシェル履歴に表示されてしまいます。)", + "prompt": "スペースで区切られたニーモニックを入力してください (\"\")" + }, + "arg_mnemonic_password": { + "help": "これは、ほぼ間違いなくあなたが探している引数ではありません。キーストアのパスワードではなく、ニーモニックのパスワードです。 最初にこれを使用せずにパスワードを提供すると、キー (資金) が失われる可能性があります! また、最初にこのツールを使用してニーモニックを生成した場合は、ニーモニックパスワードを使用しなかったことに注意してください。 ただし、ニーモニックのセキュリティを「向上させる」ためにパスワードを使用したことが確実であれば、ここで入力します。", + "confirm": "ニーモニックパスワードを使用したことは間違いありませんか? (ニーモニックパスワードはキーストアのパスワードとは異なります! 使用するべきでないときにこのパスワードを使用すると、資金が失われる可能性があります! 確認のために繰り返し入力してください。" + }, + "arg_validator_start_index": { + "help": "さらにキーの生成を開始するインデックス(キー番号)を入力します。 たとえば、過去に4つのキーを生成した場合は、ここに4と入力します。", + "prompt": "さらにキーの生成を開始するインデックス(キー番号)を入力します。 たとえば、過去に4つのキーを生成した場合は、ここに4と入力します。", + "confirm": "確認のために繰り返し入力してください。" + } + } +} diff --git a/eth2deposit/intl/ja/cli/generate_keys.json b/eth2deposit/intl/ja/cli/generate_keys.json new file mode 100644 index 00000000..2a147b9d --- /dev/null +++ b/eth2deposit/intl/ja/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "生成するバリデーターキーの数 (後からいつでも追加で生成できます)", + "prompt": "実行したいバリデーターの数を選択してください" + }, + "chain": { + "help": "ターゲットとしている eth2 のバージョン。ETH を入金する場合は \"mainnet\" を使用してください。", + "prompt": "(mainnet または testnet) ネットワーク/チェーン名を選択してください" + }, + "keystore_password": { + "help": "キーを生成するために使用したニーモニック。 (この引数を使用せずにCLIからニーモニックの入力が求められるのを待つことをお勧めします。そうしないとシェル履歴に表示されます。)", + "prompt": "キーストアを保護するパスワード。eth2 バリデーターをセットアップする際に復号化するためにこれを再入力する必要があります。", + "confirm": "確認のために繰り返し入力してください。", + "mismatch": "エラー:入力された2つの値が一致しません。もう一度入力してください。" + } + }, + "generate_keys": { + "msg_key_creation": "キーを作成しています。", + "msg_creation_success": "\n成功しました!\nあなたのキーは次の場所で見つけることができます:", + "msg_pause": "\n任意のキーを押してください。", + "err_verify_keystores": "キーストアの確認に失敗しました。", + "err_verify_deposit": "入金データ JSON ファイルの確認に失敗しました。" + } +} diff --git a/eth2deposit/intl/ja/cli/new_mnemonic.json b/eth2deposit/intl/ja/cli/new_mnemonic.json new file mode 100644 index 00000000..e5cadaac --- /dev/null +++ b/eth2deposit/intl/ja/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "新しいニーモニックとキーを生成" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "ニーモニックの言語", + "prompt": "ニーモニックの言語を選択してください" + }, + "msg_mnemonic_presentation": "これはあなたのニーモニック (シードフレーズ) です。書き留めて安全な場所に保管してください。これはあなたのデポジットを取得するための唯一の方法です。", + "msg_press_any_key": "ニーモニックを書き留めたら任意のキーを押してください。", + "msg_mnemonic_retype_prompt": "書き留めた内容を確認するには、スペースで区切ってニーモニックを入力してください。" + } +} diff --git a/eth2deposit/intl/ja/credentials.json b/eth2deposit/intl/ja/credentials.json new file mode 100644 index 00000000..cd0ae78a --- /dev/null +++ b/eth2deposit/intl/ja/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "キーを作成しています:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "キーストアを作成しています:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "デポジットデータを作成しています:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "キーストアを確認しています:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ja/deposit.json b/eth2deposit/intl/ja/deposit.json new file mode 100644 index 00000000..1b75d8ad --- /dev/null +++ b/eth2deposit/intl/ja/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Python のバージョンが最新ではありません。バージョン 3.7 以降をインストールしてください。" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ja/utils/validation.json b/eth2deposit/intl/ja/utils/validation.json new file mode 100644 index 00000000..e674fe58 --- /dev/null +++ b/eth2deposit/intl/ja/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "入金確認中:" + }, + "validate_password_strength": { + "msg_password_length": "パスワードの長さは少なくとも8文字でなければなりません。再入力してください" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ko/cli/existing_mnemonic.json b/eth2deposit/intl/ko/cli/existing_mnemonic.json new file mode 100644 index 00000000..fbb3d810 --- /dev/null +++ b/eth2deposit/intl/ko/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "유효한 니모닉이 아닙니다. 오타가 있는지 확인하세요." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "기존 니모닉에서 키 생성(또는 복구)" + }, + "arg_mnemonic": { + "help": "키를 생성할 때 사용한 니모닉입니다. (이 인수를 사용하지 말고 CLI가 니모닉을 요청할 때까지 기다리는 것이 좋습니다. 기다리지 않으면 셸 기록에 표시되기 때문입니다.)", + "prompt": "니모닉을 공백(\" \")으로 구분하여 입력하세요." + }, + "arg_mnemonic_password": { + "help": "찾고 계신 인수가 확실히 아닌 것 같습니다. 니모닉 비밀번호이지, 키스토어 비밀번호가 아닙니다. 초기에 사용하지 않은 비밀번호를 여기 입력하면 키(당연히 자금도!)를 잃어버릴 수 있습니다. 이 도구를 사용하여 니모닉을 처음 생성한다면 니모닉 비밀번호를 사용한 적이 없을 것입니다. 니모닉의 보안을 \"강화\"하려는 목적으로 비밀번호를 사용했다는 것이 확실할 때만 이 도구를 사용하시기 바랍니다.", + "confirm": "니모닉 비밀번호를 사용한 적이 있다고 확실히 확신하십니까? (키스토어 비밀번호와 다른 것입니다!) 착오로 인해 사용하면 자금을 잃어버릴 수 있습니다! 확인을 위해 동일하게 입력" + }, + "arg_validator_start_index": { + "help": "키를 추가로 생성하기 시작할 인덱스(생성 완료된 키 개수)를 입력하세요. 과거에 생성한 키가 총 4개라면 여기에 4를 입력하면 됩니다.", + "prompt": "키를 추가로 생성하기 시작할 인덱스(생성 완료된 키 개수)를 입력하세요. 과거에 생성한 키가 총 4개라면 여기에 4를 입력하면 됩니다.", + "confirm": "확인을 위해 동일하게 입력" + } + } +} diff --git a/eth2deposit/intl/ko/cli/generate_keys.json b/eth2deposit/intl/ko/cli/generate_keys.json new file mode 100644 index 00000000..84e20266 --- /dev/null +++ b/eth2deposit/intl/ko/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "생성하려는 검증자 키의 개수(나중에 언제든 생성 가능)", + "prompt": "실행하려는 검증자의 개수를 선택하세요." + }, + "chain": { + "help": "타겟팅하려는 eth2의 버전입니다. ETH를 예치한다면 \"mainnet\"을 사용하세요.", + "prompt": "(메인넷 또는 테스트넷) 네트워크/체인 이름을 선택하세요." + }, + "keystore_password": { + "help": "키스토어를 안전하게 보호하는 비밀번호입니다. eth2 검증자를 셋업할 때 다시 입력하여 복호화해야 합니다. (이 인수를 사용하지 말고 CLI가 니모닉을 요청할 때까지 기다리는 것이 좋습니다. 기다리지 않으면 셸 기록에 표시되기 때문입니다.)", + "prompt": "키스토어를 안전하게 보호하는 비밀번호입니다. eth2 검증자를 셋업할 때 다시 입력하여 복호화해야 합니다.", + "confirm": "확인을 위해 동일하게 입력", + "mismatch": "오류: 입력한 두 값이 일치하지 않습니다. 다시 입력하세요." + } + }, + "generate_keys": { + "msg_key_creation": "키 생성 중입니다.", + "msg_creation_success": "\n성공!\n키를 찾을 수 있는 위치: ", + "msg_pause": "\n\n아무 키나 누르세요.", + "err_verify_keystores": "키스토어를 검증하지 못했습니다.", + "err_verify_deposit": "예치금 데이터 JSON 파일을 검증하지 못했습니다." + } +} diff --git a/eth2deposit/intl/ko/cli/new_mnemonic.json b/eth2deposit/intl/ko/cli/new_mnemonic.json new file mode 100644 index 00000000..b8a5c6f3 --- /dev/null +++ b/eth2deposit/intl/ko/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "새 니모닉 및 키 생성" + }, + "arg_mnemonic_language": { + "default": "한국어", + "help": "니모닉이 작성된 언어", + "prompt": "니모닉 언어를 선택하세요." + }, + "msg_mnemonic_presentation": "귀하의 니모닉(시드 문구)입니다. 적어두고 안전한 곳에 보관하세요. 예치금을 찾을 수 있는 유일한 수단입니다.", + "msg_press_any_key": "니모닉을 다 적으면 아무 키나 누르세요.", + "msg_mnemonic_retype_prompt": "니모닉을 입력(공백으로 구분)하여 적은 내용을 확인하세요." + } +} diff --git a/eth2deposit/intl/ko/credentials.json b/eth2deposit/intl/ko/credentials.json new file mode 100644 index 00000000..16c256b5 --- /dev/null +++ b/eth2deposit/intl/ko/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "키 생성 중:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "키스토어 생성 중:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "예치금 데이터 생성 중:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "키스토어 검증 중:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ko/deposit.json b/eth2deposit/intl/ko/deposit.json new file mode 100644 index 00000000..8bb4a274 --- /dev/null +++ b/eth2deposit/intl/ko/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Python 버전이 너무 낮습니다. 3.7 이상 버전을 설치하세요." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ko/utils/validation.json b/eth2deposit/intl/ko/utils/validation.json new file mode 100644 index 00000000..1c309db3 --- /dev/null +++ b/eth2deposit/intl/ko/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "예치금 검증 중:\t" + }, + "validate_password_strength": { + "msg_password_length": "비밀번호는 8자 이상이어야 합니다. 다시 입력하세요." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/pt-BR/cli/existing_mnemonic.json b/eth2deposit/intl/pt-BR/cli/existing_mnemonic.json new file mode 100644 index 00000000..f96548e5 --- /dev/null +++ b/eth2deposit/intl/pt-BR/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "Isso não é um mnemônico válido. Verifique se há erros de digitação." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Gerar (ou recuperar) chaves a partir de um mnemônico existente" + }, + "arg_mnemonic": { + "help": "O mnemônico que você usou para gerar suas chaves. (Recomenda-se não usar este argumento e esperar até que a CLI pergunte pelo seu mnemônico; caso contrário, ele aparecerá no seu histórico do shell.)", + "prompt": "Por favor, digite seu mnemônico separado por espaços (\" \")" + }, + "arg_mnemonic_password": { + "help": "Este, quase com certeza, não é o argumento que você está procurando: é para senhas mnemônicas, não para senhas do keystore. Se você fornecer uma senha aqui e não tiver usado uma inicialmente, poderá perder suas chaves (e, portanto, seus fundos!). Note também que se você tiver usado essa ferramenta para gerar seu mnemônico inicial, então não usou uma senha mnemônica. Porém, se tiver certeza de ter usado uma senha para \"aumentar\" a segurança do seu mnemônico, digite-a aqui.", + "confirm": "Você tem certeza absoluta de ter usado uma senha mnemônica? (não é igual a uma senha do keystore!). Se você usar uma num momento inadequado, pode sofrer uma perda de fundos! Repita para confirmar" + }, + "arg_validator_start_index": { + "help": "Digite o índice (número de chave) a partir do qual deseja gerar mais chaves. Por exemplo, se você gerou 4 chaves antes, digite 4 aqui.", + "prompt": "Digite o índice (número de chave) a partir do qual deseja gerar mais chaves. Por exemplo, se você gerou 4 chaves antes, digite 4 aqui.", + "confirm": "Repita para confirmar" + } + } +} diff --git a/eth2deposit/intl/pt-BR/cli/generate_keys.json b/eth2deposit/intl/pt-BR/cli/generate_keys.json new file mode 100644 index 00000000..45298f6d --- /dev/null +++ b/eth2deposit/intl/pt-BR/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "A quantidade de chaves de validadores que você deseja gerar (poderá gerar mais depois)", + "prompt": "Por favor, escolha quantos validadores deseja executar" + }, + "chain": { + "help": "A versão de eth2 do seu interesse. Use \"mainnet\" se estiver depositando ETH", + "prompt": "Selecione o nome da rede/cadeia (mainnet ou testnet)" + }, + "keystore_password": { + "help": "A senha que protegerá seus keystores. Você precisará digitá-la para descriptografá-los ao configurar seus validadores eth2. (Recomenda-se não usar esse argumento e esperar que a CLI solicite o seu mnemônico; caso contrário, aparecerá no histórico do shell.)", + "prompt": "A senha que protegerá seus keystores. Você precisará digitá-la para descriptografá-los ao configurar seus validadores eth2.", + "confirm": "Repita para confirmar", + "mismatch": "Erro: os dois valores inseridos não coincidem. Digite-os novamente." + } + }, + "generate_keys": { + "msg_key_creation": "Criando suas chaves.", + "msg_creation_success": "\nSuccesso!\nSuas chaves se encontram em: ", + "msg_pause": "\n\nPressione qualquer tecla.", + "err_verify_keystores": "Não foi possível verificar os keystores.", + "err_verify_deposit": "Não foi possível verificar os dados JSON do depósito." + } +} diff --git a/eth2deposit/intl/pt-BR/cli/new_mnemonic.json b/eth2deposit/intl/pt-BR/cli/new_mnemonic.json new file mode 100644 index 00000000..dbada945 --- /dev/null +++ b/eth2deposit/intl/pt-BR/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Gerar um novo mnemônico e chaves" + }, + "arg_mnemonic_language": { + "default": "Português", + "help": "A linguagem do seu mnemônico", + "prompt": "Por favor, escolha o idioma do seu mnemônico" + }, + "msg_mnemonic_presentation": "Este é o seu mnemônico (frase semente). Anote-o e armazene-o de maneira segura, pois será a ÚNICA maneira de recuperar o seu depósito.", + "msg_press_any_key": "Pressione qualquer tecla quando tiver anotado o mnemônico.", + "msg_mnemonic_retype_prompt": "Por favor, digite seu mnemônico (separado por espaços) para confirmar que o anotou" + } +} diff --git a/eth2deposit/intl/pt-BR/credentials.json b/eth2deposit/intl/pt-BR/credentials.json new file mode 100644 index 00000000..953a3ce2 --- /dev/null +++ b/eth2deposit/intl/pt-BR/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Criação das suas chaves:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Criação dos seus keystores:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Criação dos seus dados de depósito:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Verificação dos seus keystores:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/pt-BR/deposit.json b/eth2deposit/intl/pt-BR/deposit.json new file mode 100644 index 00000000..4b2fa17e --- /dev/null +++ b/eth2deposit/intl/pt-BR/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Sua versão do python é insuficiente, por favor instale a versão 3.7 ou superior." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/pt-BR/utils/validation.json b/eth2deposit/intl/pt-BR/utils/validation.json new file mode 100644 index 00000000..f3caa042 --- /dev/null +++ b/eth2deposit/intl/pt-BR/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Verificação dos seus depósitos:\t" + }, + "validate_password_strength": { + "msg_password_length": "A senha deve ter pelo menos 8 caracteres. Por favor, digite-a novamente" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ro/cli/existing_mnemonic.json b/eth2deposit/intl/ro/cli/existing_mnemonic.json new file mode 100644 index 00000000..88e1f557 --- /dev/null +++ b/eth2deposit/intl/ro/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "Acesta nu este un mnemonic corect, verifică dacă e scris corect." + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "Generează (sau recuperează) chei dintr-un mnemonic existent" + }, + "arg_mnemonic": { + "help": "Mnemonicul cu care ai generat cheile. (Îți recomandăm să nu folosești acest argument, ci să aștepți ca interfața linie de comandă să-ți ceară mnemonicul, altfel acesta o să apară în istoricul comenzilor de shell.)", + "prompt": "Introdu mnemonicul, separat cu spații („ ”)" + }, + "arg_mnemonic_password": { + "help": "Aproape sigur acesta nu este argumentul pe care îl cauți: este vorba despre parole de mnemonice, nu despre parolele de cheie. Dacă introduci aici o parolă, în condițiile în care inițial nu ai folosit parolă, poate duce la pierderi de chei (și, prin urmare, de fonduri)! De reținut: dacă ați folosit acest instrument la generarea inițială a mnemonicului, atunci nu ai folosit parolă de mnemonic. În schimb, dacă știi sigur că ai creat o parolă pentru „a îmbunătăți” securitatea mnemonicului, acesta este locul în care trebuie s-o introduci.", + "confirm": "Știi absolut sigur că ai folosit o parolă de mnemonic? (Aceasta este diferită de parola depozitului de chei!) Dacă folosești parolă atunci când nu e cazul, poți să pierzi fonduri! Repetă parola, pentru confirmare" + }, + "arg_validator_start_index": { + "help": "Introdu indexul (numărul de cheie) de la care vrei să începi să generezi mai multe chei. De exemplu, dacă ai generat 4 chei în trecut, aici trebuie să introduci 4.", + "prompt": "Introdu indexul (numărul de cheie) de la care vrei să începi să generezi mai multe chei. De exemplu, dacă ai generat 4 chei în trecut, aici trebuie să introduci 4.", + "confirm": "Repetă parola, pentru confirmare" + } + } +} diff --git a/eth2deposit/intl/ro/cli/generate_keys.json b/eth2deposit/intl/ro/cli/generate_keys.json new file mode 100644 index 00000000..0747a226 --- /dev/null +++ b/eth2deposit/intl/ro/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "Numărul de chei de validator pe care vrei să le generezi (poți genera oricând mai multe)", + "prompt": "Alege câți validatori vrei să rulezi" + }, + "chain": { + "help": "Versiunea de eth2 țintă. Dacă depui ETH, folosește „mainnet”", + "prompt": "Alege numele de rețea/lanț (mainnet sau testnet)" + }, + "keystore_password": { + "help": "Parola cu care securizezi depozitele de chei. Va trebui să o introduci din nou pentru a le decripta atunci când configurezi validatorii eth2. (Îți recomandăm să nu folosești acest argument, ci să aștepți ca interfața linie de comandă să-ți ceară mnemonicul, altfel acesta o să apară în istoricul comenzilor de shell.)", + "prompt": "Parola cu care vei securiza depozitele de chei. Va trebui să o reintroduci pentru a le decripta atunci când configurezi validatorii eth2.", + "confirm": "Repetă parola, pentru confirmare", + "mismatch": "Eroare: cele două valori introduse sunt diferite. Te rugăm să tastezi din nou." + } + }, + "generate_keys": { + "msg_key_creation": "Se creează cheile.", + "msg_creation_success": "\nReușită!\nCheile se găsesc la: ", + "msg_pause": "\n\nApară o tastă oarecare.", + "err_verify_keystores": "Verificarea depozitelor de chei nu a reușit.", + "err_verify_deposit": "Verificarea datelor de depunere a fişierelor JSON a eşuat." + } +} diff --git a/eth2deposit/intl/ro/cli/new_mnemonic.json b/eth2deposit/intl/ro/cli/new_mnemonic.json new file mode 100644 index 00000000..be50f3c1 --- /dev/null +++ b/eth2deposit/intl/ro/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "Generează un nou mnemonic și chei" + }, + "arg_mnemonic_language": { + "default": "english", + "help": "Limba mnemonicului", + "prompt": "Alege limba mnemonicului" + }, + "msg_mnemonic_presentation": "Acesta este mnemonicul (fraza sămânță). Scrie-l și păstrează-l în siguranță, este SINGURA cale de a prelua depunerea.", + "msg_press_any_key": "După ce ți-ai notat mnemonicul, apasă orice tastă.", + "msg_mnemonic_retype_prompt": "Tastează mnemonicul (separat cu spații) pentru a confirma faptul că ți l-ai notat" + } +} diff --git a/eth2deposit/intl/ro/credentials.json b/eth2deposit/intl/ro/credentials.json new file mode 100644 index 00000000..f179e1f2 --- /dev/null +++ b/eth2deposit/intl/ro/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "Se creează cheile:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "Se creează depozitele de chei:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "Se creează datele de depozit:\t" + }, + "verify_keystores": { + "msg_keystore_verification": "Se verifică depozitele de chei:\t" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ro/deposit.json b/eth2deposit/intl/ro/deposit.json new file mode 100644 index 00000000..991b5070 --- /dev/null +++ b/eth2deposit/intl/ro/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "Versiunea de python este prea veche, te rugăm să instalezi versiunea 3.7 sau una mai recentă." + } +} \ No newline at end of file diff --git a/eth2deposit/intl/ro/utils/validation.json b/eth2deposit/intl/ro/utils/validation.json new file mode 100644 index 00000000..ad69a6d5 --- /dev/null +++ b/eth2deposit/intl/ro/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "Se verifică depozitele tale:\t" + }, + "validate_password_strength": { + "msg_password_length": "Parola trebuie să aibă o lungime de cel puțin 8. Te rugăm să o reintroduci" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/zh-CN/cli/existing_mnemonic.json b/eth2deposit/intl/zh-CN/cli/existing_mnemonic.json new file mode 100644 index 00000000..e07fac43 --- /dev/null +++ b/eth2deposit/intl/zh-CN/cli/existing_mnemonic.json @@ -0,0 +1,23 @@ +{ + "validate_mnemonic": { + "err_invalid_mnemonic": "这不是一个有效的助记符,请检查有无打字错误。" + }, + "existing_mnemonic": { + "arg_existing_mnemonic": { + "help": "从现有助记符中生成(或恢复)密钥" + }, + "arg_mnemonic": { + "help": "用来生成您密钥的助记符。(建议不要使用此参数,而是等待 CLI 要求您提供您的助记符,否则它将出现在您的 shell 历史中。)", + "prompt": "请输入您的助记符,用空格(“ ”)分隔" + }, + "arg_mnemonic_password": { + "help": "这几乎肯定不是您想要的参数:这里要的是助记密码,而不是密钥库密码。如果您在这里提供一个密码(若您起初没有启用密码),则可能会导致密钥丢失(从而造成资金损失)! 还请注意,如果您起初使用此工具生成了您的助记符,则说明您就没有启用助记密码。然而,如果您确定使用了密码来“增加”您助记符的安全性,则您可以在这里提供一个密码。", + "confirm": "您是否绝对肯定您启用了助记密码?(这不同于密钥库密码!) 如果您不确定启用了助记密码而硬要输入,则可能会造成资金损失! 重复输入以确认" + }, + "arg_validator_start_index": { + "help": "输入您想要开始生成更多密钥的索引(密钥号码)。例如,如果您在过去生成了 4 个密钥,请在此处输入 4。", + "prompt": "输入您想要开始生成更多密钥的索引(密钥号码)。例如,如果您在过去生成了 4 个密钥,请在此处输入 4。", + "confirm": "重复输入以确认" + } + } +} diff --git a/eth2deposit/intl/zh-CN/cli/generate_keys.json b/eth2deposit/intl/zh-CN/cli/generate_keys.json new file mode 100644 index 00000000..e14ba731 --- /dev/null +++ b/eth2deposit/intl/zh-CN/cli/generate_keys.json @@ -0,0 +1,25 @@ +{ + "generate_keys_arguments_decorator": { + "num_validators": { + "help": "您想要生成的验证者密钥数量(您以后随时可以生成更多密钥)", + "prompt": "请选择您想要运行多少验证者" + }, + "chain": { + "help": "您正在对准的 eth2 版本。如果您要存入以太币,请使用 \"mainnet\"", + "prompt": "请选择(主网或测试网)网络名/链名" + }, + "keystore_password": { + "help": "用来保护您密钥库的密码。您在设置您的 eth2 验证者时需要重新输入密码以便解密它们。(建议不要使用此参数,而是等待 CLI 要求您提供您的助记符,否则它将出现在您的 shell 历史中。)", + "prompt": "用来保护您密钥库的密码。您在设置您的 eth2 验证者时需要重新输入密码以便解密它们。", + "confirm": "重复输入以确认", + "mismatch": "错误:输入的两个值不匹配。请再次输入。" + } + }, + "generate_keys": { + "msg_key_creation": "正在创建您的密钥。", + "msg_creation_success": "\n成功!\n您的密钥可以在这里找到: ", + "msg_pause": "\n\n按任意键。", + "err_verify_keystores": "无法验证密钥库。", + "err_verify_deposit": "无法验证存款数据 JSON 文件。" + } +} diff --git a/eth2deposit/intl/zh-CN/cli/new_mnemonic.json b/eth2deposit/intl/zh-CN/cli/new_mnemonic.json new file mode 100644 index 00000000..1766ea4e --- /dev/null +++ b/eth2deposit/intl/zh-CN/cli/new_mnemonic.json @@ -0,0 +1,15 @@ +{ + "new_mnemonic": { + "arg_new_mnemonic": { + "help": "生成一个新的助记符和密钥" + }, + "arg_mnemonic_language": { + "default": "简体中文", + "help": "您的助记符所使用的语言", + "prompt": "请选择您的助记符语言" + }, + "msg_mnemonic_presentation": "这是您的助记符(助记词)。请记下它并存放在安全的地方,它是取回您存款的唯一方式。", + "msg_press_any_key": "在您记下助记符后,按任意键。", + "msg_mnemonic_retype_prompt": "请输入您的助记符(用空格分隔)以确认您已记下了" + } +} diff --git a/eth2deposit/intl/zh-CN/credentials.json b/eth2deposit/intl/zh-CN/credentials.json new file mode 100644 index 00000000..15c7bddc --- /dev/null +++ b/eth2deposit/intl/zh-CN/credentials.json @@ -0,0 +1,14 @@ +{ + "from_mnemonic": { + "msg_key_creation": "正在创建您的密钥:\t\t" + }, + "export_keystores": { + "msg_keystore_creation": "正在创建您的密钥库:\t" + }, + "export_deposit_data_json": { + "msg_depositdata_creation": "正在创建您的存款数据:" + }, + "verify_keystores": { + "msg_keystore_verification": "正在验证您的密钥库:" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/zh-CN/deposit.json b/eth2deposit/intl/zh-CN/deposit.json new file mode 100644 index 00000000..6d8766e2 --- /dev/null +++ b/eth2deposit/intl/zh-CN/deposit.json @@ -0,0 +1,5 @@ +{ + "check_python_version": { + "err_python_version": "您的 python 版本不足,请安装 3.7 或以上版本。" + } +} \ No newline at end of file diff --git a/eth2deposit/intl/zh-CN/utils/validation.json b/eth2deposit/intl/zh-CN/utils/validation.json new file mode 100644 index 00000000..f13801f2 --- /dev/null +++ b/eth2deposit/intl/zh-CN/utils/validation.json @@ -0,0 +1,8 @@ +{ + "verify_deposit_data_json": { + "msg_deposit_verification": "正在验证您的存款:\t" + }, + "validate_password_strength": { + "msg_password_length": "密码长度至少应为 8。请重新输入" + } +} \ No newline at end of file diff --git a/eth2deposit/key_handling/key_derivation/mnemonic.py b/eth2deposit/key_handling/key_derivation/mnemonic.py index 756ec5eb..3e3b0d1f 100644 --- a/eth2deposit/key_handling/key_derivation/mnemonic.py +++ b/eth2deposit/key_handling/key_derivation/mnemonic.py @@ -5,9 +5,11 @@ from typing import ( Optional, Sequence, - Tuple, ) +from eth2deposit.utils.constants import ( + MNEMONIC_LANG_OPTIONS, +) from eth2deposit.utils.crypto import ( SHA256, PBKDF2, @@ -69,23 +71,12 @@ def get_seed(*, mnemonic: str, password: str) -> bytes: return PBKDF2(password=encoded_mnemonic, salt=salt, dklen=64, c=2048, prf='sha512') -def get_languages(path: str) -> Tuple[str, ...]: - """ - Walk the `path` and list all the languages with word-lists available. - """ - path = _resource_path(path) - (_, _, filenames) = next(os.walk(path)) - filenames = [f for f in filenames if f[-4:] == '.txt'] - languages = tuple([name[:-4] for name in filenames]) - return languages - - def determine_mnemonic_language(mnemonic: str, words_path: str) -> Sequence[str]: """ Given a `mnemonic` determine what language[s] it is written in. There are collisions between word-lists, so multiple candidate languages are returned. """ - languages = get_languages(words_path) + languages = MNEMONIC_LANG_OPTIONS.keys() word_language_map = {word: lang for lang in languages for word in _get_word_list(lang, words_path)} try: mnemonic_list = mnemonic.split(' ') diff --git a/eth2deposit/utils/click.py b/eth2deposit/utils/click.py new file mode 100644 index 00000000..e10fad46 --- /dev/null +++ b/eth2deposit/utils/click.py @@ -0,0 +1,116 @@ +import click +from typing import ( + Any, + Callable, + Optional, + Sequence, + Tuple, + Union, +) + +from eth2deposit.exceptions import ValidationError +from eth2deposit.utils import config + + +def _value_of(f: Union[Callable[[], Any], Any]) -> Any: + ''' + If the input, f, is a function, return f(), else return f. + ''' + return(f() if callable(f) else f) + + +class JITOption(click.Option): + ''' + A click.Option, except certain values are recomputed before they are used. + ''' + def __init__( + self, + param_decls: str, + default: Union[Callable[[], Any], None, Any] = None, + help: Union[Callable[[], str], str, None] = None, + prompt: Union[Callable[[], str], str, None] = None, + **kwargs: Any, + ): + + self.callable_default = default + self.callable_help = help + self.callable_prompt = prompt + + return super().__init__( + param_decls=[_value_of(param_decls)], + default=_value_of(default), + help=_value_of(help), + prompt=_value_of(prompt), + **kwargs, + ) + + def prompt_for_value(self, ctx: click.Context) -> Any: + self.prompt = _value_of(self.callable_prompt) + return super().prompt_for_value(ctx) + + def get_help_record(self, ctx: click.Context) -> Tuple[str, str]: + self.help = _value_of(self.callable_help) + return super().get_help_record(ctx) + + def get_default(self, ctx: click.Context) -> Any: + self.default = _value_of(self.callable_default) + return super().get_default(ctx) + + +def jit_option(*args: Any, **kwargs: Any) -> Callable[[Any], Any]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + + def decorator(f: Callable[[Any], Any]) -> Callable[[Any], Any]: + click.decorators._param_memo(f, JITOption(*args, **kwargs)) # type: ignore + return f + + return decorator + + +def captive_prompt_callback( + processing_func: Callable[[str], Any], + prompt: Callable[[], str], + confirmation_prompt: Optional[Callable[[], str]]=None, + confirmation_mismatch_msg: Callable[[], str]=lambda: '', + hide_input: bool=False, +) -> Callable[[click.Context, str, str], Any]: + ''' + Traps the user in a prompt until the value chosen is acceptable + as defined by `processing_func` not returning a ValidationError + :param processing_func: A function to process the user's input that possibly raises a ValidationError + :param prompt: the text to prompt the user with, should their input raise an error when passed to processing_func() + :param confirmation_prompt: the optional prompt for confirming user input (the user must repeat their input) + :param confirmation_mismatch_msg: the message displayed to the user should their input and confirmation not match + :param hide_input: bool, hides the input as the user types + ''' + def callback(ctx: click.Context, param: Any, user_input: str) -> Any: + if config.non_interactive: + return processing_func(user_input) + while True: + try: + processed_input = processing_func(user_input) + # Logic for confirming user input: + if confirmation_prompt is not None and processed_input != '': + confirmation_input = click.prompt(confirmation_prompt(), hide_input=hide_input) + if processing_func(confirmation_input) != processed_input: + raise ValidationError(confirmation_mismatch_msg()) + return processed_input + except ValidationError as e: + click.echo(e) + user_input = click.prompt(prompt(), hide_input=hide_input) + return callback + + +def choice_prompt_func(prompt_func: Callable[[], str], choices: Sequence[str]) -> Callable[[], str]: + ''' + Formats the prompt and choices in a printable manner. + ''' + return lambda: '%s %s: ' % (prompt_func(), choices) diff --git a/eth2deposit/utils/config.py b/eth2deposit/utils/config.py new file mode 100644 index 00000000..2dce13cd --- /dev/null +++ b/eth2deposit/utils/config.py @@ -0,0 +1,6 @@ +''' +This file contains global variables to required to parameterise click functionality +''' + +language = 'en' # The CLI language selected by the user +non_interactive = False # Whether or not to interactively prompt the user for input. (Useful for tests and debugging) diff --git a/eth2deposit/utils/constants.py b/eth2deposit/utils/constants.py index 13d1d629..d0a71b20 100644 --- a/eth2deposit/utils/constants.py +++ b/eth2deposit/utils/constants.py @@ -1,4 +1,8 @@ import os +from typing import ( + Dict, + List, +) ZERO_BYTES32 = b'\x00' * 32 @@ -17,6 +21,46 @@ WORD_LISTS_PATH = os.path.join('eth2deposit', 'key_handling', 'key_derivation', 'word_lists') DEFAULT_VALIDATOR_KEYS_FOLDER_NAME = 'validator_keys' +# Internationalisation constants +INTL_CONTENT_PATH = os.path.join('eth2deposit', 'intl') + + +def _add_index_to_options(d: Dict[str, List[str]]) -> Dict[str, List[str]]: + ''' + Adds the (1 indexed) index (in the dict) to the first element of value list. + eg. {'en': ['English', 'en']} -> {'en': ['1. English', '1', 'English', 'en']} + Requires dicts to be ordered (Python > 3.6) + ''' + keys = list(d.keys()) # Force copy dictionary keys top prevent iteration over changing dict + for i, key in enumerate(keys): + d.update({key: ['%s. %s' % (i + 1, d[key][0]), str(i + 1)] + d[key]}) + return d + + +INTL_LANG_OPTIONS = _add_index_to_options({ + 'ar': ['العربية', 'ar', 'Arabic'], + 'el': ['ελληνικά', 'el', 'Greek'], + 'en': ['English', 'en'], + 'fr': ['Français', 'Francais', 'fr', 'French'], + 'id': ['Bahasa melayu', 'Melayu', 'id', 'Malay'], + 'it': ['Italiano', 'it', 'Italian'], + 'ja': ['日本語', 'ja', 'Japanese'], + 'ko': ['한국어', '조선말', '韓國語', 'ko', 'Korean'], + 'pt-BR': ['Português do Brasil', 'Brasil', 'pt-BR', 'Brazilian Portuguese'], + 'ro': ['român', 'limba română', 'ro', 'Romainian'], + 'zh-CN': ['简体中文', 'zh-CN', 'zh', 'Chinease'], +}) +MNEMONIC_LANG_OPTIONS = _add_index_to_options({ + 'chinese_simplified': ['简体中文', 'zh', 'zh-CN', 'Chinese Simplified'], + 'chinese_traditional': ['繁體中文', 'zh-tw', 'Chinese Traditional'], + 'czech': ['čeština', 'český jazyk', 'cs', 'Czech'], + 'english': ['English', 'en'], + 'italian': ['Italiano', 'it', 'Italian'], + 'korean': ['한국어', '조선말', '韓國語', 'ko', 'Korean'], + # Portuguese mnemonics are in both pt & pt-BR + 'portuguese': ['Português', 'Português do Brasil', 'pt', 'pt-BR', 'Portuguese'], + 'spanish': ['Español', 'es', 'Spanish'], +}) # Sundry constants UNICODE_CONTROL_CHARS = list(range(0x00, 0x20)) + list(range(0x7F, 0xA0)) diff --git a/eth2deposit/utils/intl.py b/eth2deposit/utils/intl.py new file mode 100644 index 00000000..43242d4b --- /dev/null +++ b/eth2deposit/utils/intl.py @@ -0,0 +1,95 @@ +import inspect +import difflib +from functools import reduce +import json +from typing import ( + Any, + Dict, + Iterable, + List, + Mapping, + Sequence, +) +import os + +from eth2deposit.utils import config +from eth2deposit.utils.constants import ( + INTL_CONTENT_PATH, +) +from eth2deposit.exceptions import ValidationError + + +def _get_from_dict(dataDict: Dict[str, Any], mapList: Iterable[str]) -> str: + ''' + Iterate nested dictionaries + ''' + try: + ans = reduce(dict.get, mapList, dataDict) + assert isinstance(ans, str) + return ans + except TypeError: + raise KeyError('%s not in internationalisation json file.' % mapList) + except AssertionError: + raise KeyError('The provided params (%s) were incomplete.' % mapList) + + +def load_text(params: List[str], file_path: str='', func: str='', lang: str='') -> str: + ''' + Determine and return the appropriate internationalisation text for a given set of `params`. + ''' + if file_path == '': + # Auto-detect file-path based on call stack + file_path = inspect.stack()[1].filename + file_path = file_path[:-3] + '.json' # replace .py with .json + + if func == '': + # Auto-detect function based on call stack + func = inspect.stack()[1].function + + if lang == '': + lang = config.language + + # Determine path to json text + file_path_list = os.path.normpath(file_path).split(os.path.sep) + rel_path_list = file_path_list[file_path_list.index('eth2deposit') + 1:] + json_path = os.path.join(INTL_CONTENT_PATH, lang, *rel_path_list) + + try: + # browse json until text is found + with open(json_path) as f: + text_dict = json.load(f) + return _get_from_dict(text_dict, [func] + params) + except (KeyError, FileNotFoundError): + # If text not found in lang, try return English version + if lang == 'en': + raise KeyError('%s not in %s file' % ([func] + params, json_path)) + return load_text(params, file_path, func, 'en') + + +def get_first_options(options: Mapping[str, Sequence[str]]) -> List[str]: + ''' + Returns the first `option` in the values of the `options` dict. + ''' + return list(map(lambda x: x[0], options.values())) + + +def closest_match(text: str, options: Iterable[str]) -> str: + ''' + Finds the closest match to `text` in the `options_list` + ''' + match = difflib.get_close_matches(text, options, n=1, cutoff=0.6) + if len(match) == 0: + raise ValidationError('%s is not a valid language option' % text) + return match[0] + + +def fuzzy_reverse_dict_lookup(text: str, options: Mapping[str, Sequence[str]]) -> str: + ''' + Returns the closest match to `text` out of the `options` + :param text: The test string that needs to be found + :param options: A dict with keys (the value that will be returned) + and values a list of the options to be matched against + ''' + reverse_lookup_dict = {value: key for key, values in options.items() for value in values} + match = closest_match(text, reverse_lookup_dict.keys()) + return reverse_lookup_dict[match] diff --git a/eth2deposit/utils/validation.py b/eth2deposit/utils/validation.py index 23a513d8..414d1681 100644 --- a/eth2deposit/utils/validation.py +++ b/eth2deposit/utils/validation.py @@ -9,6 +9,7 @@ from py_ecc.bls import G2ProofOfPossession as bls from eth2deposit.exceptions import ValidationError +from eth2deposit.utils.intl import load_text from eth2deposit.utils.ssz import ( compute_deposit_domain, compute_signing_root, @@ -33,7 +34,7 @@ def verify_deposit_data_json(filefolder: str, credentials: Sequence[Credential]) """ with open(filefolder, 'r') as f: deposit_json = json.load(f) - with click.progressbar(deposit_json, label='Verifying your deposits:\t', + with click.progressbar(deposit_json, label=load_text(['msg_deposit_verification']), show_percent=False, show_pos=True) as deposits: return all([validate_deposit(deposit, credential) for deposit, credential in zip(deposits, credentials)]) return False @@ -94,6 +95,20 @@ def validate_deposit(deposit_data_dict: Dict[str, Any], credential: Credential) return signed_deposit.hash_tree_root == deposit_message_root -def validate_password_strength(password: str) -> None: +def validate_password_strength(password: str) -> str: if len(password) < 8: - raise ValidationError(f"The password length should be at least 8. Got {len(password)}.") + raise ValidationError(load_text(['msg_password_length'])) + return password + + +def validate_int_range(num: Any, low: int, high: int) -> int: + ''' + Verifies that `num` is an `int` andlow <= num < high + ''' + try: + num_int = int(num) # Try cast to int + assert num_int == float(num) # Check num is not float + assert low <= num_int < high # Check num in range + return num_int + except (ValueError, AssertionError): + raise ValidationError(load_text(['err_not_positive_integer'])) diff --git a/requirements_test.txt b/requirements_test.txt index 7e042617..c3f58171 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -107,3 +107,6 @@ iniconfig==1.0.1 \ toml==0.10.1 \ --hash=sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f \ --hash=sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88 +jsonschema==3.2.0 \ + --hash=sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163 \ + --hash=sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a diff --git a/test_binary_script.py b/test_binary_script.py index 81e4f625..4c6e747f 100755 --- a/test_binary_script.py +++ b/test_binary_script.py @@ -19,7 +19,10 @@ async def main(argv): run_script_cmd = './' + binary_file_path + '/deposit' cmd_args = [ - run_script_cmd + ' new-mnemonic', + run_script_cmd, + '--language', 'english', + '--non_interactive', + 'new-mnemonic', '--num_validators', '1', '--mnemonic_language', 'english', '--chain', 'mainnet', @@ -36,7 +39,7 @@ async def main(argv): parsing = False async for out in proc.stdout: output = out.decode('utf-8').rstrip() - if output.startswith("This is your seed phrase."): + if output.startswith("This is your mnemonic"): parsing = True elif output.startswith("Please type your mnemonic"): parsing = False diff --git a/test_deposit_script.py b/test_deposit_script.py index e4682642..356cde49 100755 --- a/test_deposit_script.py +++ b/test_deposit_script.py @@ -24,7 +24,10 @@ async def main(): print('[INFO] Installed') cmd_args = [ - run_script_cmd + ' new-mnemonic', + run_script_cmd, + '--language', 'english', + '--non_interactive', + 'new-mnemonic', '--num_validators', '1', '--mnemonic_language', 'english', '--chain', 'mainnet', @@ -41,7 +44,7 @@ async def main(): parsing = False async for out in proc.stdout: output = out.decode('utf-8').rstrip() - if output.startswith("This is your seed phrase."): + if output.startswith("This is your mnemonic"): parsing = True elif output.startswith("Please type your mnemonic"): parsing = False diff --git a/tests/test_cli/test_existing_menmonic.py b/tests/test_cli/test_existing_menmonic.py index 2ecc97c2..2740426e 100644 --- a/tests/test_cli/test_existing_menmonic.py +++ b/tests/test_cli/test_existing_menmonic.py @@ -21,10 +21,16 @@ def test_existing_mnemonic_bls_withdrawal() -> None: runner = CliRunner() inputs = [ + 'TREZOR', 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', - '2', '2', '5', 'mainnet', 'MyPassword', 'MyPassword', 'yes'] + '2', '2', '5', 'mainnet', 'MyPassword', 'MyPassword'] data = '\n'.join(inputs) - arguments = ['existing-mnemonic', '--folder', my_folder_path, '--mnemonic-password', 'TREZOR'] + arguments = [ + '--language', 'english', + 'existing-mnemonic', + '--folder', my_folder_path, + '--mnemonic-password', 'TREZOR', + ] result = runner.invoke(cli, arguments, input=data) assert result.exit_code == 0 @@ -57,11 +63,13 @@ def test_existing_mnemonic_eth1_address_withdrawal() -> None: runner = CliRunner() inputs = [ + 'TREZOR', 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', - '2', '2', '5', 'mainnet', 'MyPassword', 'MyPassword', 'yes'] + '2', '2', '5', 'mainnet', 'MyPassword', 'MyPassword'] data = '\n'.join(inputs) eth1_withdrawal_address = '0x00000000219ab540356cbb839cbe05303d7705fa' arguments = [ + '--language', 'english', 'existing-mnemonic', '--folder', my_folder_path, '--mnemonic-password', 'TREZOR', @@ -118,6 +126,8 @@ async def test_script() -> None: cmd_args = [ run_script_cmd, + '--language', 'english', + '--non_interactive', 'existing-mnemonic', '--num_validators', '1', '--mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"', @@ -129,15 +139,8 @@ async def test_script() -> None: ] proc = await asyncio.create_subprocess_shell( ' '.join(cmd_args), - stdin=asyncio.subprocess.PIPE, - stdout=asyncio.subprocess.PIPE, ) - - async for out in proc.stdout: - output = out.decode('utf-8').rstrip() - if output.startswith('Running deposit-cli...'): - proc.stdin.write(b'y\n') - + await proc.wait() # Check files validator_keys_folder_path = os.path.join(my_folder_path, DEFAULT_VALIDATOR_KEYS_FOLDER_NAME) _, _, key_files = next(os.walk(validator_keys_folder_path)) diff --git a/tests/test_cli/test_new_mnemonic.py b/tests/test_cli/test_new_mnemonic.py index 4ff1d644..94496360 100644 --- a/tests/test_cli/test_new_mnemonic.py +++ b/tests/test_cli/test_new_mnemonic.py @@ -10,6 +10,7 @@ from eth2deposit.cli import new_mnemonic from eth2deposit.deposit import cli from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME, ETH1_ADDRESS_WITHDRAWAL_PREFIX +from eth2deposit.utils.intl import load_text from .helpers import clean_key_folder, get_permissions, get_uuid @@ -27,7 +28,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str: os.mkdir(my_folder_path) runner = CliRunner() - inputs = ['english', '1', 'mainnet', 'MyPassword', 'MyPassword', 'fakephrase'] + inputs = ['english', 'english', '1', 'mainnet', 'MyPassword', 'MyPassword', 'fakephrase'] data = '\n'.join(inputs) result = runner.invoke(cli, ['new-mnemonic', '--folder', my_folder_path], input=data) assert result.exit_code == 0 @@ -70,6 +71,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str: data = '\n'.join(inputs) eth1_withdrawal_address = '0x00000000219ab540356cbb839cbe05303d7705fa' arguments = [ + '--language', 'english', 'new-mnemonic', '--folder', my_folder_path, '--eth1_withdrawal_address', eth1_withdrawal_address, @@ -124,7 +126,10 @@ async def test_script() -> None: await proc.wait() cmd_args = [ - run_script_cmd + ' new-mnemonic', + run_script_cmd, + '--language', 'english', + '--non_interactive', + 'new-mnemonic', '--num_validators', '5', '--mnemonic_language', 'english', '--chain', 'mainnet', @@ -139,11 +144,12 @@ async def test_script() -> None: seed_phrase = '' parsing = False + mnemonic_json_file = os.path.join(os.getcwd(), 'eth2deposit/../eth2deposit/cli/', 'new_mnemonic.json') async for out in proc.stdout: output = out.decode('utf-8').rstrip() - if output.startswith("This is your seed phrase."): + if output.startswith(load_text(['msg_mnemonic_presentation'], mnemonic_json_file, 'new_mnemonic')): parsing = True - elif output.startswith("Please type your mnemonic"): + elif output.startswith(load_text(['msg_mnemonic_retype_prompt'], mnemonic_json_file, 'new_mnemonic')): parsing = False elif parsing: seed_phrase += output diff --git a/tests/test_cli/test_regeneration.py b/tests/test_cli/test_regeneration.py index 8f5dac73..2c27892b 100644 --- a/tests/test_cli/test_regeneration.py +++ b/tests/test_cli/test_regeneration.py @@ -33,7 +33,7 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str: runner = CliRunner() # Create index 0 and 1 my_password = "MyPassword" - inputs = ['english', '2', 'mainnet', my_password, my_password, mock_mnemonic] + inputs = ['english', 'english', '2', 'mainnet', my_password, my_password, mock_mnemonic] data = '\n'.join(inputs) result = runner.invoke(cli, ['new-mnemonic', '--folder', folder_path_1], input=data) assert result.exit_code == 0 @@ -56,8 +56,9 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str: runner = CliRunner() # Create index 1 and 2 inputs = [ + 'english', mock_mnemonic, - '1', '1', '2', 'mainnet', 'MyPassword', 'MyPassword', 'yes'] + '1', '1', '2', 'mainnet', 'MyPassword', 'MyPassword'] data = '\n'.join(inputs) arguments = ['existing-mnemonic', '--folder', folder_path_2] result = runner.invoke(cli, arguments, input=data) diff --git a/tests/test_intl/schemas/cli/existing_mnemonic.json b/tests/test_intl/schemas/cli/existing_mnemonic.json new file mode 100644 index 00000000..a90d8159 --- /dev/null +++ b/tests/test_intl/schemas/cli/existing_mnemonic.json @@ -0,0 +1,92 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "validate_mnemonic": { + "type": "object", + "properties": { + "err_invalid_mnemonic": { + "type": "string" + } + }, + "required": [ + "err_invalid_mnemonic" + ] + }, + "existing_mnemonic": { + "type": "object", + "properties": { + "arg_existing_mnemonic": { + "type": "object", + "properties": { + "help": { + "type": "string" + } + }, + "required": [ + "help" + ] + }, + "arg_mnemonic": { + "type": "object", + "properties": { + "help": { + "type": "string" + }, + "prompt": { + "type": "string" + } + }, + "required": [ + "help", + "prompt" + ] + }, + "arg_mnemonic_password": { + "type": "object", + "properties": { + "help": { + "type": "string" + }, + "confirm": { + "type": "string" + } + }, + "required": [ + "help", + "confirm" + ] + }, + "arg_validator_start_index": { + "type": "object", + "properties": { + "help": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "confirm":{ + "type": "string" + } + }, + "required": [ + "help", + "prompt", + "confirm" + ] + } + }, + "required": [ + "arg_existing_mnemonic", + "arg_mnemonic", + "arg_mnemonic_password", + "arg_validator_start_index" + ] + } + }, + "required": [ + "validate_mnemonic", + "existing_mnemonic" + ] +} \ No newline at end of file diff --git a/tests/test_intl/schemas/cli/generate_keys.json b/tests/test_intl/schemas/cli/generate_keys.json new file mode 100644 index 00000000..84384b8b --- /dev/null +++ b/tests/test_intl/schemas/cli/generate_keys.json @@ -0,0 +1,108 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "generate_keys_arguments_decorator": { + "type": "object", + "properties": { + "num_validators": { + "type": "object", + "properties": { + "help": { + "type": "string" + }, + "prompt": { + "type": "string" + } + }, + "required": [ + "help", + "prompt" + ] + }, + "folder": { + "type": "object", + "properties": { + "help": { + "type": "string" + } + } + }, + "chain": { + "type": "object", + "properties": { + "help": { + "type": "string" + }, + "prompt": { + "type": "string" + } + }, + "required": [ + "help", + "prompt" + ] + }, + "keystore_password": { + "type": "object", + "properties": { + "help": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "confirm": { + "type": "string" + }, + "mismatch": { + "type": "string" + } + }, + "required": [ + "help", + "prompt", + "confirm", + "mismatch" + ] + } + }, + "required": [ + "num_validators", + "chain", + "keystore_password" + ] + }, + "generate_keys": { + "type": "object", + "properties": { + "msg_key_creation": { + "type": "string" + }, + "msg_creation_success": { + "type": "string" + }, + "msg_pause": { + "type": "string" + }, + "err_verify_keystores": { + "type": "string" + }, + "err_verify_deposit": { + "type": "string" + } + }, + "required": [ + "msg_key_creation", + "msg_creation_success", + "msg_pause", + "err_verify_keystores", + "err_verify_deposit" + ] + } + }, + "required": [ + "generate_keys_arguments_decorator", + "generate_keys" + ] +} \ No newline at end of file diff --git a/tests/test_intl/schemas/cli/new_mnemonic.json b/tests/test_intl/schemas/cli/new_mnemonic.json new file mode 100644 index 00000000..42c438d5 --- /dev/null +++ b/tests/test_intl/schemas/cli/new_mnemonic.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "new_mnemonic": { + "type": "object", + "properties": { + "arg_new_mnemonic": { + "type": "object", + "properties": { + "help": { + "type": "string" + } + }, + "required": [ + "help" + ] + }, + "arg_mnemonic_language": { + "type": "object", + "properties": { + "default": { + "type": "string" + }, + "help": { + "type": "string" + }, + "prompt": { + "type": "string" + } + }, + "required": [ + "default", + "help", + "prompt" + ] + }, + "msg_mnemonic_presentation": { + "type": "string" + }, + "msg_press_any_key": { + "type": "string" + }, + "msg_mnemonic_retype_prompt": { + "type": "string" + } + }, + "required": [ + "arg_new_mnemonic", + "arg_mnemonic_language", + "msg_mnemonic_presentation", + "msg_press_any_key", + "msg_mnemonic_retype_prompt" + ] + } + }, + "required": [ + "new_mnemonic" + ] +} \ No newline at end of file diff --git a/tests/test_intl/schemas/credentials.json b/tests/test_intl/schemas/credentials.json new file mode 100644 index 00000000..ccc844ab --- /dev/null +++ b/tests/test_intl/schemas/credentials.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "from_mnemonic": { + "type": "object", + "properties": { + "msg_key_creation": { + "type": "string" + } + }, + "required": [ + "msg_key_creation" + ] + }, + "export_keystores": { + "type": "object", + "properties": { + "msg_keystore_creation": { + "type": "string" + } + }, + "required": [ + "msg_keystore_creation" + ] + }, + "export_deposit_data_json": { + "type": "object", + "properties": { + "msg_depositdata_creation": { + "type": "string" + } + }, + "required": [ + "msg_depositdata_creation" + ] + }, + "verify_keystores": { + "type": "object", + "properties": { + "msg_keystore_verification": { + "type": "string" + } + }, + "required": [ + "msg_keystore_verification" + ] + } + }, + "required": [ + "from_mnemonic", + "export_keystores", + "export_deposit_data_json", + "verify_keystores" + ] +} \ No newline at end of file diff --git a/tests/test_intl/schemas/deposit.json b/tests/test_intl/schemas/deposit.json new file mode 100644 index 00000000..ea7773aa --- /dev/null +++ b/tests/test_intl/schemas/deposit.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "check_python_version": { + "type": "object", + "properties": { + "err_python_version": { + "type": "string" + } + }, + "required": [ + "err_python_version" + ] + } + }, + "required": [ + "check_python_version" + ] +} \ No newline at end of file diff --git a/tests/test_intl/schemas/utils/validation.json b/tests/test_intl/schemas/utils/validation.json new file mode 100644 index 00000000..3078d70b --- /dev/null +++ b/tests/test_intl/schemas/utils/validation.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "verify_deposit_data_json": { + "type": "object", + "properties": { + "msg_deposit_verification": { + "type": "string" + } + }, + "required": [ + "msg_deposit_verification" + ] + }, + "validate_password_strength": { + "type": "object", + "properties": { + "msg_password_length": { + "type": "string" + } + }, + "required": [ + "msg_password_length" + ] + } + }, + "required": [ + "verify_deposit_data_json", + "validate_password_strength" + ] +} \ No newline at end of file diff --git a/tests/test_intl/test_json_schema.py b/tests/test_intl/test_json_schema.py new file mode 100644 index 00000000..24f0db3c --- /dev/null +++ b/tests/test_intl/test_json_schema.py @@ -0,0 +1,45 @@ +import json +import jsonschema +import os +import pytest +import re +from typing import ( + List, +) + +from eth2deposit.utils.constants import INTL_CONTENT_PATH + + +TEST_SCHEMAS_FOLDER = os.path.join(os.path.dirname(__file__), 'schemas') + + +def files_to_check(root_dir: str) -> List[str]: + file_list = [] + for dir_, _, files in os.walk(root_dir): + for file_name in files: + rel_dir = os.path.relpath(dir_, root_dir) + rel_file = os.path.join(rel_dir, file_name) + file_list.append(rel_file) + return file_list + + +def languages_to_check(root_dir: str) -> List[str]: + dirs = next(os.walk(root_dir))[1] + regex = re.compile('([A-Za-z]){2}(-([A-Za-z]){2})?') + return [d for d in dirs if re.fullmatch(regex, d)] + + +@pytest.mark.parametrize( + 'lang, schema_path', + [ + (lang, schema) + for schema in files_to_check(TEST_SCHEMAS_FOLDER) + for lang in languages_to_check(INTL_CONTENT_PATH) + ] +) +def test_language_schemas(lang: str, schema_path: str) -> None: + with open(os.path.join(TEST_SCHEMAS_FOLDER, schema_path)) as schema_file: + schema = json.load(schema_file) + with open(os.path.join(INTL_CONTENT_PATH, lang, schema_path)) as lang_file: + lang_json = json.load(lang_file) + jsonschema.validate(lang_json, schema) diff --git a/tests/test_key_handling/test_key_derivation/test_mnemonic.py b/tests/test_key_handling/test_key_derivation/test_mnemonic.py index 51f6d335..b5096105 100644 --- a/tests/test_key_handling/test_key_derivation/test_mnemonic.py +++ b/tests/test_key_handling/test_key_derivation/test_mnemonic.py @@ -5,10 +5,12 @@ Sequence, ) +from eth2deposit.utils.constants import ( + MNEMONIC_LANG_OPTIONS, +) from eth2deposit.key_handling.key_derivation.mnemonic import ( _index_to_word, _get_word_list, - get_languages, get_seed, get_mnemonic, verify_mnemonic, @@ -16,7 +18,7 @@ WORD_LISTS_PATH = os.path.join(os.getcwd(), 'eth2deposit', 'key_handling', 'key_derivation', 'word_lists') -all_languages = get_languages(WORD_LISTS_PATH) +all_languages = MNEMONIC_LANG_OPTIONS.keys() test_vector_filefolder = os.path.join('tests', 'test_key_handling', 'test_key_derivation', 'test_vectors', 'mnemonic.json') diff --git a/tests/test_utils/test_constants.py b/tests/test_utils/test_constants.py new file mode 100644 index 00000000..06652127 --- /dev/null +++ b/tests/test_utils/test_constants.py @@ -0,0 +1,18 @@ +import pytest +from typing import ( + Dict, + List, +) + +from eth2deposit.utils.constants import _add_index_to_options + + +@pytest.mark.parametrize( + 'arg, test', [ + ({'en': ['English', 'en']}, {'en': ['1. English', '1', 'English', 'en']}), + ({'a': ['a'], 'b': ['b'], 'c': ['c']}, + {'a': ['1. a', '1', 'a'], 'b': ['2. b', '2', 'b'], 'c': ['3. c', '3', 'c']}) + ] +) +def test_add_index_to_options(arg: Dict[str, List[str]], test: Dict[str, List[str]]) -> None: + assert _add_index_to_options(arg) == test diff --git a/tests/test_utils/test_intl.py b/tests/test_utils/test_intl.py new file mode 100644 index 00000000..cec72300 --- /dev/null +++ b/tests/test_utils/test_intl.py @@ -0,0 +1,71 @@ +import os +import pytest +from typing import ( + List, +) + +from eth2deposit.utils.constants import ( + INTL_LANG_OPTIONS, + MNEMONIC_LANG_OPTIONS, +) +from eth2deposit.utils.intl import ( + fuzzy_reverse_dict_lookup, + get_first_options, + load_text, +) + + +@pytest.mark.parametrize( + 'params, file_path, func, lang, found_str', [ + (['arg_mnemonic_language', 'prompt'], os.path.join('eth2deposit', 'cli', 'new_mnemonic.json'), + 'new_mnemonic', 'en', 'Please choose your mnemonic language'), + (['arg_mnemonic_language', 'prompt'], os.path.join('eth2deposit', 'cli', 'new_mnemonic.json'), + 'new_mnemonic', 'ja', 'ニーモニックの言語を選択してください'), + ] +) +def test_load_text(params: List[str], file_path: str, func: str, lang: str, found_str: str) -> None: + assert found_str in load_text(params, file_path, func, lang) + + +@pytest.mark.parametrize( + 'params, file_path, func, lang, valid', [ + (['arg_mnemonic_language', 'prompt'], os.path.join('eth2deposit', 'cli', 'new_mnemonic.json'), + 'new_mnemonic', 'zz', True), # invalid language, should revert to english + (['arg_mnemonic_language'], os.path.join('eth2deposit', 'cli', 'new_mnemonic.json'), + 'new_mnemonic', 'en', False), # incomplete params + (['arg_mnemonic_language', 'prompt'], os.path.join('eth2deposit', 'cli', 'invalid.json'), + 'new_mnemonic', 'en', False), # invalid json path + (['arg_mnemonic_language', 'prompt'], os.path.join('eth2deposit', 'cli', 'invalid.json'), + 'new_mnemonic', 'zz', False), # invalid json path in invalid language + ] +) +def test_load_text_en_fallover(params: List[str], file_path: str, func: str, lang: str, valid: bool) -> None: + if valid: + assert load_text(params, file_path, func, lang) == load_text(params, file_path, func, 'en') + else: + try: + load_text(params, file_path, func, lang) + except KeyError: + pass + else: + assert False + + +@pytest.mark.parametrize( + 'options, first_options', [ + ({'a': ['a', 1], 'b': range(5), 'c': [chr(i) for i in range(65, 90)]}, ['a', 0, 'A']), + ] +) +def test_get_first_options(options, first_options): + assert get_first_options(options) == first_options + + +@pytest.mark.parametrize( + 'test, match, options', [ + ('English', 'english', MNEMONIC_LANG_OPTIONS), + ('한국어', 'korean', MNEMONIC_LANG_OPTIONS), + ('Roman', 'ro', INTL_LANG_OPTIONS), + ] +) +def test_fuzzy_reverse_dict_lookup(test, match, options): + assert fuzzy_reverse_dict_lookup(test, options) == match diff --git a/tests/test_utils/test_validation.py b/tests/test_utils/test_validation.py index 69e190dd..2608000a 100644 --- a/tests/test_utils/test_validation.py +++ b/tests/test_utils/test_validation.py @@ -1,7 +1,13 @@ import pytest +from typing import ( + Any, +) from eth2deposit.exceptions import ValidationError -from eth2deposit.utils.validation import validate_password_strength +from eth2deposit.utils.validation import ( + validate_int_range, + validate_password_strength, +) @pytest.mark.parametrize( @@ -17,3 +23,23 @@ def test_validate_password_strength(password, valid): else: with pytest.raises(ValidationError): validate_password_strength(password=password) + + +@pytest.mark.parametrize( + 'num, low, high, valid', + [ + (2, 0, 4, True), + (0, 0, 4, True), + (-1, 0, 4, False), + (4, 0, 4, False), + (0.2, 0, 4, False), + ('0', 0, 4, True), + ('a', 0, 4, False), + ] +) +def test_validate_int_range(num: Any, low: int, high: int, valid: bool) -> None: + if valid: + validate_int_range(num, low, high) + else: + with pytest.raises(ValidationError): + validate_int_range(num, low, high)