Skip to content

Commit

Permalink
work on the CLI interface
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBuchanan314 committed Feb 29, 2024
1 parent 58dddaf commit 9d64478
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 13 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,6 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# millipds data dir (should only end up here during local testing of dev builds)
data/
5 changes: 4 additions & 1 deletion millipds_dev.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ RUN chown -R millipds src/
USER millipds
RUN python3 -m pip install -v src/

# this doesn't do anything yet, but one day it will
RUN python3 -m millipds init dev.millipds.test --sandbox

# do the thing
CMD python3 -m millipds --host=0.0.0.0 --port=8123
CMD python3 -m millipds run --listen_host=0.0.0.0 --listen_port=8123

EXPOSE 8123/tcp
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies = [
"aiohttp",
"aiohttp_cors",
"pyjwt[crypto]==2.8.0", # bind to a specific version because jwt_monkeypatch might break!
"docopt",
]

[project.optional-dependencies]
Expand Down
57 changes: 49 additions & 8 deletions src/millipds/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,39 @@
import argparse
"""millipds CLI
Usage:
millipds init <hostname> [--sandbox]
millipds config [--appview_url=URL] [--appview_did=DID]
millipds run [--sock_path=PATH] [--listen_host=HOST] [--listen_port=PORT]
millipds (-h | --help)
millipds --version
Init:
Initialise the database. Must be done before any other commands will work.
This also sets the config options to their defaults.
hostname The public-facing hostname of this PDS, e.g. "bsky.social"
--sandbox Set config options to work with the bsky "sandbox" network. Otherwise, default to bsky prod.
Config:
Any options not specified will be left at their previous values. Once changes
have been made (or even if they haven't), the new config will be printed.
--appview_url=URL AppView URL prefix e.g. "https://api.bsky-sandbox.dev"
Run:
Launch the service (in the foreground)
--sock_path=PATH UNIX domain socket to listen on (supersedes host and port options if specified)
--listen_host=HOST Hostname to listen on [default: 127.0.0.1]
--listen_port=PORT TCP port to listen on [default: 8123]
General options:
-h --help Show this screen.
--version Show version.
"""

from docopt import docopt
import importlib.metadata
import asyncio

from . import service
Expand All @@ -7,14 +42,20 @@
This is the entrypoint for the `millipds` command (declared in project.scripts)
"""
def main():
parser = argparse.ArgumentParser(description="millipds service")
parser.add_argument("--sock_path", help="unix domain socket to listen on (supersedes HOST and PORT options)")
parser.add_argument("--host", default="127.0.0.1", help="defaults to 127.0.0.1")
parser.add_argument("--port", type=int, default=8123, help="defaults to 8123")

args = parser.parse_args()
args = docopt(__doc__, version=f"millipds version {importlib.metadata.version('millipds')}")

asyncio.run(service.run(sock_path=args.sock_path, host=args.host, port=args.port))
if args["init"]:
print("TODO INIT", args)
elif args["config"]:
print("TODO CONFIG", args)
elif args["run"]:
asyncio.run(service.run(
sock_path=args["--sock_path"],
host=args["--listen_host"],
port=int(args["--listen_port"])
))
else:
print("CLI arg parse error?!")

"""
This is the entrypoint for python3 -m millipds
Expand Down
19 changes: 15 additions & 4 deletions src/millipds/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature, encode_dss_signature
from cryptography.exceptions import InvalidSignature

"""
This is scary hand-rolled cryptography, because there aren't really any alternative
options in the python ecosystem. pyca/crytography won't add low-s support unless
openssl itself supports it, and pyjwt depends on pyca/cryptography.
Note for future maintainers (most likely me):
snarfed/arroba and MarshalX/atproto are using copy-pasted versions of this logic,
keep them in the loop if there are any important changes to be made.
"""


CURVE_ORDER = {
# constant defined by NIST SP 800-186 - https://csrc.nist.gov/pubs/sp/800/186/final
ec.SECP256R1: 0xFFFFFFFF_00000000_FFFFFFFF_FFFFFFFF_BCE6FAAD_A7179E84_F3B9CAC2_FC632551,
Expand All @@ -12,16 +23,16 @@
}


def apply_low_s_mitigation(signature: bytes, curve: ec.EllipticCurve) -> bytes:
r, s = decode_dss_signature(signature)
def apply_low_s_mitigation(dss_sig: bytes, curve: ec.EllipticCurve) -> bytes:
r, s = decode_dss_signature(dss_sig)
n = CURVE_ORDER[type(curve)]
if s > n // 2:
s = n - s
return encode_dss_signature(r, s)


def assert_dss_sig_is_low_s(signature: bytes, curve: ec.EllipticCurve) -> None:
_, s = decode_dss_signature(signature)
def assert_dss_sig_is_low_s(dss_sig: bytes, curve: ec.EllipticCurve) -> None:
_, s = decode_dss_signature(dss_sig)
n = CURVE_ORDER[type(curve)]
if s > n // 2:
raise InvalidSignature("high-S signature")
Expand Down

0 comments on commit 9d64478

Please sign in to comment.