Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
simonlindholm committed Apr 3, 2021
1 parent 62c5580 commit da00dd3
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 160 deletions.
2 changes: 1 addition & 1 deletion pah.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
from src.net.main import main
from src.net.cmd.main import main

main()
16 changes: 4 additions & 12 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
from .candidate import CandidateResult
from .compiler import Compiler
from .error import CandidateConstructionFailure
from .net.auth import fetch_servers_and_grant, run_vouch, setup
from .net.client import connect_to_servers
from .net.common import MAX_PRIO, MIN_PRIO
from .net.client import start_client
from .net.common import connect, MAX_PRIO, MIN_PRIO
from .permuter import (
EvalError,
EvalResult,
Expand Down Expand Up @@ -344,12 +343,9 @@ def run_inner(options: Options, heartbeat: Callable[[], None]) -> List[int]:
# Connect to network and create client threads
net_threads: List[threading.Thread] = []
if options.use_network:
config = setup()
servers, grant = fetch_servers_and_grant(config)
net_threads = connect_to_servers(
config = connect()
net_threads = start_client(
config,
servers,
grant,
context.permuters,
task_queue,
feedback_queue,
Expand Down Expand Up @@ -558,10 +554,6 @@ def main() -> None:
if not threads and not args.use_network:
threads = 1

if args.vouch:
run_vouch(args.directories[0])
return

options = Options(
directories=args.directories,
show_errors=args.show_errors,
Expand Down
65 changes: 6 additions & 59 deletions src/net/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@
)


def _random_name() -> str:
return "".join(random.choice(string.ascii_lowercase) for _ in range(5))


def _ask(msg: str, *, default: bool) -> bool:
if default:
msg += " (Y/n)? "
Expand Down Expand Up @@ -59,68 +55,19 @@ def _get_request(config: Config, path: str) -> bytes:
return ret


def _initial_setup(config: RawConfig) -> None:
print(
"Using permuter@home requires someone to give you access to a central -J server."
)
print()

signing_key: Optional[SigningKey] = config.signing_key
if not signing_key or not _ask("Keep previous secret key", default=True):
signing_key = SigningKey.generate()
config.signing_key = signing_key
write_config(config)
verify_key = signing_key.verify_key

nickname: Optional[str] = config.initial_setup_nickname
if not nickname or not _ask(f"Keep previous nickname [{nickname}]", default=True):
default_nickname = os.environ.get("USER") or _random_name()
nickname = (
input(f"Nickname [default: {default_nickname}]: ") or default_nickname
)
config.initial_setup_nickname = nickname
write_config(config)

signed_nickname = sign_with_magic(b"NICK", signing_key, nickname.encode("utf-8"))

vouch_data = verify_key.encode() + signed_nickname
vouch_text = base64.b64encode(vouch_data).decode("utf-8")
print("Ask someone to run the following command:")
print(f"./permuter.py --vouch {vouch_text}")
print()
print("They should give you a token back in return. Paste that here:")
inp = input().strip()

try:
token = base64.b64decode(inp.encode("utf-8"))
data = SealedBox(signing_key.to_curve25519_private_key()).decrypt(token)
auth_verify_key = VerifyKey(data[:32])
auth_server = data[32:].decode("utf-8")
print(f"Server URL: {auth_server}")
print("Testing connection...")
time.sleep(1)

# TODO: verify that contacting auth server works and signs its messages

print("permuter@home successfully set up!")
print()
config.auth_server = auth_server
config.auth_verify_key = auth_verify_key
config.initial_setup_nickname = None
write_config(config)
except Exception:
print("Invalid token!")
sys.exit(1)


def setup() -> Config:
raw_config = read_config()
if (
not raw_config.auth_verify_key
or not raw_config.signing_key
or not raw_config.auth_server
):
_initial_setup(raw_config)
print(
"Using permuter@home requires someone to give you access to a central -J server.\n"
"Run `./pah.py setup` to set this up."
)
sys.exit(1)

assert (
raw_config.auth_verify_key and raw_config.signing_key and raw_config.auth_server
), "set by _initial_setup"
Expand Down
6 changes: 3 additions & 3 deletions src/net/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,15 @@ def run(self) -> None:
self._sock.close()


def connect_to_servers(
def start_client(
config: Config,
servers: List[RemoteServer],
grant: bytes,
permuters: List[Permuter],
task_queue: "multiprocessing.Queue[Task]",
feedback_queue: "multiprocessing.Queue[Feedback]",
priority: float,
) -> List[threading.Thread]:
grant = b""
servers: List[RemoteServer] = []
threads = []
portable_permuters = [PortablePermuter(p) for p in permuters]
if not servers:
Expand Down
Empty file added src/net/cmd/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions src/net/cmd/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import abc
from argparse import ArgumentParser, Namespace


class Command(abc.ABC):
command: str
help: str

@staticmethod
@abc.abstractmethod
def add_arguments(parser: ArgumentParser) -> None:
...

@staticmethod
@abc.abstractmethod
def run(args: Namespace) -> None:
...
40 changes: 40 additions & 0 deletions src/net/cmd/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from argparse import ArgumentParser, RawDescriptionHelpFormatter

from .run_server import RunServerCommand
from .setup import SetupCommand
from .vouch import VouchCommand


def main() -> None:
parser = ArgumentParser(
description="permuter@home - run the permuter across the Internet!\n\n"
"To use p@h as a client, just pass -J when running the permuter. "
"This script is\nonly necessary for configuration or when running a server.",
formatter_class=RawDescriptionHelpFormatter,
)

commands = [
RunServerCommand,
SetupCommand,
VouchCommand,
]

subparsers = parser.add_subparsers(metavar="<command>")
for command in commands:
subparser = subparsers.add_parser(
command.command,
help=command.help,
description=command.help,
)
command.add_arguments(subparser)
subparser.set_defaults(subcommand_handler=command.run)

args = parser.parse_args()
if "subcommand_handler" in args:
args.subcommand_handler(args)
else:
parser.print_help()


if __name__ == "__main__":
main()
89 changes: 4 additions & 85 deletions src/net/main.py → src/net/cmd/run_server.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
import abc
from argparse import ArgumentParser, Namespace, RawDescriptionHelpFormatter
from .server import ServerOptions
from .server_main import server_main
from argparse import ArgumentParser, Namespace


class Command(abc.ABC):
command: str
help: str

@staticmethod
@abc.abstractmethod
def add_arguments(parser: ArgumentParser) -> None:
...

@staticmethod
@abc.abstractmethod
def run(args: Namespace) -> None:
...
from .base import Command
from ..server import ServerOptions
from ..server_main import server_main


class RunServerCommand(Command):
Expand Down Expand Up @@ -87,70 +73,3 @@ def run(args: Namespace) -> None:
)

server_main(options)


class SetupCommand(Command):
command = "setup"
help = (
"Set up permuter@home. This will require someone else to grant you "
"access to the central server."
)

@staticmethod
def add_arguments(parser: ArgumentParser) -> None:
pass

@staticmethod
def run(args: Namespace) -> None:
pass


class VouchCommand(Command):
command = "vouch"
help = "Give someone access to the central server."

@staticmethod
def add_arguments(parser: ArgumentParser) -> None:
parser.add_argument(
"magic",
help="Opaque hex string generated by 'setup'.",
)

@staticmethod
def run(args: Namespace) -> None:
pass


def main() -> None:
parser = ArgumentParser(
description="permuter@home - run the permuter across the Internet!\n\n"
"To use p@h as a client, just pass -J when running the permuter. "
"This script is\nonly necessary for configuration or when running a server.",
formatter_class=RawDescriptionHelpFormatter,
)

commands = [
RunServerCommand,
SetupCommand,
VouchCommand,
]

subparsers = parser.add_subparsers(metavar="<command>")
for command in commands:
subparser = subparsers.add_parser(
command.command,
help=command.help,
description=command.help,
)
command.add_arguments(subparser)
subparser.set_defaults(func=command.run)

args = parser.parse_args()
if "func" in args:
args.func(args)
else:
parser.print_help()


if __name__ == "__main__":
main()
85 changes: 85 additions & 0 deletions src/net/cmd/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from argparse import ArgumentParser, Namespace
import base64
import os
import random
import string
import sys
import time
from typing import Optional

from nacl.public import SealedBox
from nacl.signing import SigningKey, VerifyKey

from .base import Command
from ..common import RawConfig, read_config, sign_with_magic, write_config
from .util import ask


class SetupCommand(Command):
command = "setup"
help = (
"Set up permuter@home. This will require someone else to grant you "
"access to the central server."
)

@staticmethod
def add_arguments(parser: ArgumentParser) -> None:
pass

@staticmethod
def run(args: Namespace) -> None:
config = read_config()
_run_initial_setup(config)


def _random_name() -> str:
return "".join(random.choice(string.ascii_lowercase) for _ in range(5))


def _run_initial_setup(config: RawConfig) -> None:
signing_key: Optional[SigningKey] = config.signing_key
if not signing_key or not ask("Keep previous secret key", default=True):
signing_key = SigningKey.generate()
config.signing_key = signing_key
write_config(config)
verify_key = signing_key.verify_key

nickname: Optional[str] = config.initial_setup_nickname
if not nickname or not ask(f"Keep previous nickname [{nickname}]", default=True):
default_nickname = os.environ.get("USER") or _random_name()
nickname = (
input(f"Nickname [default: {default_nickname}]: ") or default_nickname
)
config.initial_setup_nickname = nickname
write_config(config)

signed_nickname = sign_with_magic(b"NICK", signing_key, nickname.encode("utf-8"))

vouch_data = verify_key.encode() + signed_nickname
vouch_text = base64.b64encode(vouch_data).decode("utf-8")
print("Ask someone to run the following command:")
print(f"./permuter.py --vouch {vouch_text}")
print()
print("They should give you a token back in return. Paste that here:")
inp = input().strip()

try:
token = base64.b64decode(inp.encode("utf-8"))
data = SealedBox(signing_key.to_curve25519_private_key()).decrypt(token)
auth_verify_key = VerifyKey(data[:32])
auth_server = data[32:].decode("utf-8")
print(f"Server URL: {auth_server}")
print("Testing connection...")
time.sleep(1)

# TODO: verify that contacting auth server works and signs its messages

print("permuter@home successfully set up!")
print()
config.auth_server = auth_server
config.auth_verify_key = auth_verify_key
config.initial_setup_nickname = None
write_config(config)
except Exception:
print("Invalid token!")
sys.exit(1)
Loading

0 comments on commit da00dd3

Please sign in to comment.