Skip to content

Commit

Permalink
Merge pull request #176 from ethereum/carl_chmod
Browse files Browse the repository at this point in the history
chmod keystores and deposit_data.json to `440`
  • Loading branch information
CarlBeek authored Jan 29, 2021
2 parents 0f5b2a2 + 62e13e8 commit d45d894
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 5 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ You can find the audit report by Trail of Bits [here](https://github.com/trailof

### For Linux or MacOS users

#### File Permissions

On Unix-based systems, keystores and the `deposit_data*.json` have `440`/`-r--r-----` file permissions (user & group read only). This improves security by limiting which users and processes that have access to these files. If you are getting `permission denied` errors when handling your keystores, consider changing which user/group owns the file (with `chown`) or, if need be, change the file permissions with `chmod`.

#### Option 1. Download binary executable file

##### Step 1. Installation
Expand Down
2 changes: 2 additions & 0 deletions eth2deposit/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ def export_deposit_data_json(self, folder: str) -> str:
filefolder = os.path.join(folder, 'deposit_data-%i.json' % time.time())
with open(filefolder, 'w') as f:
json.dump(deposit_data, f, default=lambda x: x.hex())
if os.name == 'posix':
os.chmod(filefolder, int('440', 8)) # Read for owner & group
return filefolder

def verify_keystores(self, keystore_filefolders: List[str], password: str) -> bool:
Expand Down
7 changes: 5 additions & 2 deletions eth2deposit/key_handling/keystore.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
field as dataclass_field
)
import json
import os
from py_ecc.bls import G2ProofOfPossession as bls
from secrets import randbits
from typing import Any, Dict, Union
Expand Down Expand Up @@ -90,12 +91,14 @@ class Keystore(BytesDataclass):
def kdf(self, **kwargs: Any) -> bytes:
return scrypt(**kwargs) if 'scrypt' in self.crypto.kdf.function else PBKDF2(**kwargs)

def save(self, file: str) -> None:
def save(self, filefolder: str) -> None:
"""
Save self as a JSON keystore.
"""
with open(file, 'w') as f:
with open(filefolder, 'w') as f:
f.write(self.as_json())
if os.name == 'posix':
os.chmod(filefolder, int('440', 8)) # Read for owner & group

@classmethod
def from_json(cls, json_dict: Dict[Any, Any]) -> 'Keystore':
Expand Down
4 changes: 4 additions & 0 deletions tests/test_cli/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ def clean_key_folder(my_folder_path: str) -> None:
def get_uuid(key_file: str) -> str:
keystore = Keystore.from_file(key_file)
return keystore.uuid


def get_permissions(path: str, file_name: str) -> str:
return oct(os.stat(os.path.join(path, file_name)).st_mode & 0o777)
11 changes: 10 additions & 1 deletion tests/test_cli/test_existing_menmonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from eth2deposit.deposit import cli
from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME
from.helpers import clean_key_folder, get_uuid
from.helpers import clean_key_folder, get_permissions, get_uuid


def test_existing_mnemonic() -> None:
Expand Down Expand Up @@ -38,6 +38,10 @@ def test_existing_mnemonic() -> None:
]
assert len(set(all_uuid)) == 5

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'
# Clean up
clean_key_folder(my_folder_path)

Expand Down Expand Up @@ -85,5 +89,10 @@ async def test_script() -> None:
validator_keys_folder_path = os.path.join(my_folder_path, DEFAULT_VALIDATOR_KEYS_FOLDER_NAME)
_, _, key_files = next(os.walk(validator_keys_folder_path))

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'

# Clean up
clean_key_folder(my_folder_path)
12 changes: 11 additions & 1 deletion tests/test_cli/test_new_mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from eth2deposit.cli import new_mnemonic
from eth2deposit.deposit import cli
from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME
from .helpers import clean_key_folder, get_uuid
from .helpers import clean_key_folder, get_permissions, get_uuid


def test_new_mnemonic(monkeypatch) -> None:
Expand Down Expand Up @@ -40,6 +40,11 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
]
assert len(set(all_uuid)) == 1

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'

# Clean up
clean_key_folder(my_folder_path)

Expand Down Expand Up @@ -103,5 +108,10 @@ async def test_script() -> None:
]
assert len(set(all_uuid)) == 5

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'

# Clean up
clean_key_folder(my_folder_path)
12 changes: 11 additions & 1 deletion tests/test_cli/test_regeneration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from eth2deposit.cli import new_mnemonic
from eth2deposit.deposit import cli
from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME
from .helpers import clean_key_folder, get_uuid
from .helpers import clean_key_folder, get_permissions, get_uuid


def test_regeneration(monkeypatch) -> None:
Expand Down Expand Up @@ -47,6 +47,11 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
for key_file in part_1_key_files]
assert len(set(all_uuid)) == 2

# Verify file permissions
if os.name == 'posix':
for file_name in part_1_key_files:
assert get_permissions(validator_keys_folder_path_1, file_name) == '0o440'

# Part 2: existing-mnemonic
runner = CliRunner()
# Create index 1 and 2
Expand Down Expand Up @@ -78,6 +83,11 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
assert keystore_1_1['pubkey'] == keystore_2_0['pubkey']
assert keystore_1_1['path'] == keystore_2_0['path']

# Verify file permissions
if os.name == 'posix':
for file_name in part_2_key_files:
assert get_permissions(validator_keys_folder_path_2, file_name) == '0o440'

# Clean up
clean_key_folder(folder_path_1)
clean_key_folder(folder_path_2)

0 comments on commit d45d894

Please sign in to comment.