Skip to content

Commit

Permalink
Store private key file in ALEPH_IM_HOME dir #119
Browse files Browse the repository at this point in the history
  • Loading branch information
aliel authored and hoh committed Jan 12, 2023
1 parent 479667b commit 258cd58
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 9 deletions.
11 changes: 10 additions & 1 deletion src/aleph_client/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Aleph Client command-line interface.
"""

import os
from typing import Optional
from pathlib import Path

Expand All @@ -10,7 +11,7 @@
from aleph_client.types import AccountFromPrivateKey
from aleph_client.account import _load_account
from aleph_client.conf import settings
from .commands import files, message, program, help_strings, aggregate
from .commands import files, message, program, help_strings, aggregate, account


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

app.add_typer(
account.app, name="account", help="Manage account"
)

@app.command()
def whoami(
Expand All @@ -44,6 +48,11 @@ def whoami(
Display your public address.
"""

if private_key is not None:
private_key_file = None
elif private_key_file and not os.path.exists(private_key_file):
exit(0)

account: AccountFromPrivateKey = _load_account(private_key, private_key_file)
typer.echo(account.get_address())

Expand Down
3 changes: 3 additions & 0 deletions src/aleph_client/chains/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,17 @@ def get_fallback_private_key() -> bytes:
private_key = prvfile.read()
except OSError:
private_key = generate_key()
os.makedirs(os.path.dirname(settings.PRIVATE_KEY_FILE), exist_ok=True)
with open(settings.PRIVATE_KEY_FILE, "wb") as prvfile:
prvfile.write(private_key)
os.symlink(settings.PRIVATE_KEY_FILE, os.path.join(os.path.dirname(settings.PRIVATE_KEY_FILE), "default.key"))

return private_key


def delete_private_key_file():
try:
os.remove(settings.PRIVATE_KEY_FILE)
os.unlink(os.path.join(os.path.dirname(settings.PRIVATE_KEY_FILE), "default.key"))
except FileNotFoundError:
pass
50 changes: 50 additions & 0 deletions src/aleph_client/commands/account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os
import typer
import logging
from typing import Optional
from aleph_client.types import AccountFromPrivateKey
from aleph_client.chains.common import generate_key
from aleph_client.account import _load_account
from aleph_client.conf import settings

from aleph_client.commands import help_strings
from aleph_client.commands.utils import setup_logging


logger = logging.getLogger(__name__)
app = typer.Typer()


@app.command()
def create(
from_private_key: Optional[str] = typer.Option(
None, help=help_strings.PRIVATE_KEY
),
debug: bool = False,
):
"""Create or import a private key."""

setup_logging(debug)

typer.echo("Generating private key file.")
private_key_file = typer.prompt("Enter file in which to save the key", settings.PRIVATE_KEY_FILE)

if os.path.exists(private_key_file):
typer.echo(f"Error: key already exists: '{private_key_file}'")
exit(1)

private_key = None
if from_private_key is not None:
account: AccountFromPrivateKey = _load_account(private_key_str=from_private_key)
private_key = from_private_key.encode()
else:
private_key = generate_key()

if private_key is None:
typer.echo("An unexpected error occurred!")
exit(1)

os.makedirs(os.path.dirname(private_key_file), exist_ok=True)
with open(private_key_file, "wb") as prvfile:
prvfile.write(private_key)
typer.echo(f"Private key created => {private_key_file}")
23 changes: 21 additions & 2 deletions src/aleph_client/conf.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import pathlib
from pathlib import Path
from shutil import which
from typing import Optional

from pydantic import BaseSettings, Field
import os
import sys


class Settings(BaseSettings):
CONFIG_HOME: Optional[str] = None

# In case the user does not want to bother with handling private keys himself,
# do an ugly and insecure write and read from disk to this file.
PRIVATE_KEY_FILE: Path = Field(
default=Path("device.key"),
default=Path("ethereum.key"),
description="Path to the private key used to sign messages",
)

PRIVATE_KEY_STRING: Optional[str] = None
API_HOST: str = "https://api2.aleph.im"
MAX_INLINE_SIZE: int = 50000
Expand Down Expand Up @@ -42,3 +47,17 @@ class Config:

# Settings singleton
settings = Settings()

if settings.CONFIG_HOME is None:
xdg_data_home = os.environ.get("XDG_DATA_HOME")
if xdg_data_home is not None:
os.environ["ALEPH_CONFIG_HOME"] = str(Path(xdg_data_home, ".aleph-im"))
else:
home = os.path.expanduser("~")
os.environ["ALEPH_CONFIG_HOME"] = str(Path(home, ".aleph-im"))

settings = Settings()

assert settings.CONFIG_HOME
if str(settings.PRIVATE_KEY_FILE) == "ethereum.key":
settings.PRIVATE_KEY_FILE = Path(settings.CONFIG_HOME, "private-keys", "ethereum.key")
12 changes: 6 additions & 6 deletions tests/unit/test_asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
create_program,
forget,
)
from aleph_client.chains.common import get_fallback_private_key
from aleph_client.chains.common import get_fallback_private_key, delete_private_key_file
from aleph_client.chains.ethereum import ETHAccount
from aleph_client.conf import settings
from aleph_client.types import StorageEnum, MessageStatus
Expand All @@ -45,7 +45,7 @@ async def test_create_post():
_get_fallback_session.cache_clear()

if os.path.exists(settings.PRIVATE_KEY_FILE):
os.remove(settings.PRIVATE_KEY_FILE)
delete_private_key_file()

private_key = get_fallback_private_key()
account: ETHAccount = ETHAccount(private_key=private_key)
Expand Down Expand Up @@ -74,7 +74,7 @@ async def test_create_aggregate():
_get_fallback_session.cache_clear()

if os.path.exists(settings.PRIVATE_KEY_FILE):
os.remove(settings.PRIVATE_KEY_FILE)
delete_private_key_file()

private_key = get_fallback_private_key()
account: ETHAccount = ETHAccount(private_key=private_key)
Expand Down Expand Up @@ -109,7 +109,7 @@ async def test_create_store():
_get_fallback_session.cache_clear()

if os.path.exists(settings.PRIVATE_KEY_FILE):
os.remove(settings.PRIVATE_KEY_FILE)
delete_private_key_file()

private_key = get_fallback_private_key()
account: ETHAccount = ETHAccount(private_key=private_key)
Expand Down Expand Up @@ -162,7 +162,7 @@ async def test_create_program():
_get_fallback_session.cache_clear()

if os.path.exists(settings.PRIVATE_KEY_FILE):
os.remove(settings.PRIVATE_KEY_FILE)
delete_private_key_file()

private_key = get_fallback_private_key()
account: ETHAccount = ETHAccount(private_key=private_key)
Expand All @@ -188,7 +188,7 @@ async def test_forget():
_get_fallback_session.cache_clear()

if os.path.exists(settings.PRIVATE_KEY_FILE):
os.remove(settings.PRIVATE_KEY_FILE)
delete_private_key_file()

private_key = get_fallback_private_key()
account: ETHAccount = ETHAccount(private_key=private_key)
Expand Down

0 comments on commit 258cd58

Please sign in to comment.