Skip to content

Commit 258cd58

Browse files
alielhoh
authored andcommitted
Store private key file in ALEPH_IM_HOME dir #119
1 parent 479667b commit 258cd58

File tree

5 files changed

+90
-9
lines changed

5 files changed

+90
-9
lines changed

src/aleph_client/__main__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Aleph Client command-line interface.
33
"""
44

5+
import os
56
from typing import Optional
67
from pathlib import Path
78

@@ -10,7 +11,7 @@
1011
from aleph_client.types import AccountFromPrivateKey
1112
from aleph_client.account import _load_account
1213
from aleph_client.conf import settings
13-
from .commands import files, message, program, help_strings, aggregate
14+
from .commands import files, message, program, help_strings, aggregate, account
1415

1516

1617
app = typer.Typer()
@@ -30,6 +31,9 @@
3031
aggregate.app, name="aggregate", help="Manage aggregate messages on Aleph.im"
3132
)
3233

34+
app.add_typer(
35+
account.app, name="account", help="Manage account"
36+
)
3337

3438
@app.command()
3539
def whoami(
@@ -44,6 +48,11 @@ def whoami(
4448
Display your public address.
4549
"""
4650

51+
if private_key is not None:
52+
private_key_file = None
53+
elif private_key_file and not os.path.exists(private_key_file):
54+
exit(0)
55+
4756
account: AccountFromPrivateKey = _load_account(private_key, private_key_file)
4857
typer.echo(account.get_address())
4958

src/aleph_client/chains/common.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,17 @@ def get_fallback_private_key() -> bytes:
7777
private_key = prvfile.read()
7878
except OSError:
7979
private_key = generate_key()
80+
os.makedirs(os.path.dirname(settings.PRIVATE_KEY_FILE), exist_ok=True)
8081
with open(settings.PRIVATE_KEY_FILE, "wb") as prvfile:
8182
prvfile.write(private_key)
83+
os.symlink(settings.PRIVATE_KEY_FILE, os.path.join(os.path.dirname(settings.PRIVATE_KEY_FILE), "default.key"))
8284

8385
return private_key
8486

8587

8688
def delete_private_key_file():
8789
try:
8890
os.remove(settings.PRIVATE_KEY_FILE)
91+
os.unlink(os.path.join(os.path.dirname(settings.PRIVATE_KEY_FILE), "default.key"))
8992
except FileNotFoundError:
9093
pass

src/aleph_client/commands/account.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import os
2+
import typer
3+
import logging
4+
from typing import Optional
5+
from aleph_client.types import AccountFromPrivateKey
6+
from aleph_client.chains.common import generate_key
7+
from aleph_client.account import _load_account
8+
from aleph_client.conf import settings
9+
10+
from aleph_client.commands import help_strings
11+
from aleph_client.commands.utils import setup_logging
12+
13+
14+
logger = logging.getLogger(__name__)
15+
app = typer.Typer()
16+
17+
18+
@app.command()
19+
def create(
20+
from_private_key: Optional[str] = typer.Option(
21+
None, help=help_strings.PRIVATE_KEY
22+
),
23+
debug: bool = False,
24+
):
25+
"""Create or import a private key."""
26+
27+
setup_logging(debug)
28+
29+
typer.echo("Generating private key file.")
30+
private_key_file = typer.prompt("Enter file in which to save the key", settings.PRIVATE_KEY_FILE)
31+
32+
if os.path.exists(private_key_file):
33+
typer.echo(f"Error: key already exists: '{private_key_file}'")
34+
exit(1)
35+
36+
private_key = None
37+
if from_private_key is not None:
38+
account: AccountFromPrivateKey = _load_account(private_key_str=from_private_key)
39+
private_key = from_private_key.encode()
40+
else:
41+
private_key = generate_key()
42+
43+
if private_key is None:
44+
typer.echo("An unexpected error occurred!")
45+
exit(1)
46+
47+
os.makedirs(os.path.dirname(private_key_file), exist_ok=True)
48+
with open(private_key_file, "wb") as prvfile:
49+
prvfile.write(private_key)
50+
typer.echo(f"Private key created => {private_key_file}")

src/aleph_client/conf.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1+
import pathlib
12
from pathlib import Path
23
from shutil import which
34
from typing import Optional
45

56
from pydantic import BaseSettings, Field
7+
import os
8+
import sys
69

710

811
class Settings(BaseSettings):
12+
CONFIG_HOME: Optional[str] = None
13+
914
# In case the user does not want to bother with handling private keys himself,
1015
# do an ugly and insecure write and read from disk to this file.
1116
PRIVATE_KEY_FILE: Path = Field(
12-
default=Path("device.key"),
17+
default=Path("ethereum.key"),
1318
description="Path to the private key used to sign messages",
1419
)
15-
20+
1621
PRIVATE_KEY_STRING: Optional[str] = None
1722
API_HOST: str = "https://api2.aleph.im"
1823
MAX_INLINE_SIZE: int = 50000
@@ -42,3 +47,17 @@ class Config:
4247

4348
# Settings singleton
4449
settings = Settings()
50+
51+
if settings.CONFIG_HOME is None:
52+
xdg_data_home = os.environ.get("XDG_DATA_HOME")
53+
if xdg_data_home is not None:
54+
os.environ["ALEPH_CONFIG_HOME"] = str(Path(xdg_data_home, ".aleph-im"))
55+
else:
56+
home = os.path.expanduser("~")
57+
os.environ["ALEPH_CONFIG_HOME"] = str(Path(home, ".aleph-im"))
58+
59+
settings = Settings()
60+
61+
assert settings.CONFIG_HOME
62+
if str(settings.PRIVATE_KEY_FILE) == "ethereum.key":
63+
settings.PRIVATE_KEY_FILE = Path(settings.CONFIG_HOME, "private-keys", "ethereum.key")

tests/unit/test_asynchronous.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
create_program,
1919
forget,
2020
)
21-
from aleph_client.chains.common import get_fallback_private_key
21+
from aleph_client.chains.common import get_fallback_private_key, delete_private_key_file
2222
from aleph_client.chains.ethereum import ETHAccount
2323
from aleph_client.conf import settings
2424
from aleph_client.types import StorageEnum, MessageStatus
@@ -45,7 +45,7 @@ async def test_create_post():
4545
_get_fallback_session.cache_clear()
4646

4747
if os.path.exists(settings.PRIVATE_KEY_FILE):
48-
os.remove(settings.PRIVATE_KEY_FILE)
48+
delete_private_key_file()
4949

5050
private_key = get_fallback_private_key()
5151
account: ETHAccount = ETHAccount(private_key=private_key)
@@ -74,7 +74,7 @@ async def test_create_aggregate():
7474
_get_fallback_session.cache_clear()
7575

7676
if os.path.exists(settings.PRIVATE_KEY_FILE):
77-
os.remove(settings.PRIVATE_KEY_FILE)
77+
delete_private_key_file()
7878

7979
private_key = get_fallback_private_key()
8080
account: ETHAccount = ETHAccount(private_key=private_key)
@@ -109,7 +109,7 @@ async def test_create_store():
109109
_get_fallback_session.cache_clear()
110110

111111
if os.path.exists(settings.PRIVATE_KEY_FILE):
112-
os.remove(settings.PRIVATE_KEY_FILE)
112+
delete_private_key_file()
113113

114114
private_key = get_fallback_private_key()
115115
account: ETHAccount = ETHAccount(private_key=private_key)
@@ -162,7 +162,7 @@ async def test_create_program():
162162
_get_fallback_session.cache_clear()
163163

164164
if os.path.exists(settings.PRIVATE_KEY_FILE):
165-
os.remove(settings.PRIVATE_KEY_FILE)
165+
delete_private_key_file()
166166

167167
private_key = get_fallback_private_key()
168168
account: ETHAccount = ETHAccount(private_key=private_key)
@@ -188,7 +188,7 @@ async def test_forget():
188188
_get_fallback_session.cache_clear()
189189

190190
if os.path.exists(settings.PRIVATE_KEY_FILE):
191-
os.remove(settings.PRIVATE_KEY_FILE)
191+
delete_private_key_file()
192192

193193
private_key = get_fallback_private_key()
194194
account: ETHAccount = ETHAccount(private_key=private_key)

0 commit comments

Comments
 (0)