A from-scratch atproto PDS implementation in Python (mirrors https://github.com/DavidBuchanan314/millipds)

add plcsign util

+27 -4
+14 -2
src/millipds/__main__.py
··· 8 8 millipds util keygen [--p256 | --k256] 9 9 millipds util print_pubkey <signing_key_pem> 10 10 millipds util plcgen --genesis_json=PATH --rotation_key=PEM --handle=HANDLE --pds_host=URL --repo_pubkey=DIDKEY 11 + millipds util plcsign --unsigned_op=PATH --rotation_key=PEM [--prev_op=PATH] 11 12 millipds (-h | --help) 12 13 millipds --version 13 14 ··· 146 147 }, 147 148 "prev": None, 148 149 } 149 - rawsig = crypto.raw_sign(rotation_key, cbrrr.encode_dag_cbor(genesis)) 150 - genesis["sig"] = base64.urlsafe_b64encode(rawsig).decode().rstrip("=") 150 + genesis["sig"] = crypto.plc_sign(rotation_key, genesis) 151 151 genesis_digest = hashlib.sha256(cbrrr.encode_dag_cbor(genesis)).digest() 152 152 plc = "did:plc:" + base64.b32encode(genesis_digest)[:24].lower().decode() 153 153 with open(args["--genesis_json"], "w") as out: 154 154 json.dump(genesis, out, indent=4) 155 155 print(plc) 156 + elif args["plcsign"]: 157 + with open(args["--unsigned_op"]) as op_json: 158 + op = json.load(op_json) 159 + with open(args["--rotation_key"]) as pem: 160 + rotation_key = crypto.privkey_from_pem(pem.read()) 161 + if args["--prev_op"]: 162 + with open(args["--prev_op"]) as op_json: 163 + prev_op = json.load(op_json) 164 + op["prev"] = cbrrr.CID.cidv1_dag_cbor_sha256_32_from(cbrrr.encode_dag_cbor(prev_op)).encode() 165 + del op["sig"] # remove any existing sig 166 + op["sig"] = crypto.plc_sign(rotation_key, op) 167 + print(json.dumps(op, indent=4)) 156 168 else: 157 169 print("invalid util subcommand") 158 170 return
+9
src/millipds/crypto.py
··· 1 1 from typing import Literal 2 + import base64 2 3 3 4 from cryptography.hazmat.primitives.asymmetric import ec 4 5 from cryptography.hazmat.primitives import hashes ··· 10 11 from cryptography.exceptions import InvalidSignature 11 12 12 13 import base58 14 + 15 + import cbrrr 13 16 14 17 """ 15 18 This is scary hand-rolled cryptography, because there aren't really any alternative ··· 100 103 ) 101 104 multicodec = MULTICODEC_PUBKEY_PREFIX[type(pubkey.curve)] + compressed_public_bytes 102 105 return "did:key:z" + base58.b58encode(multicodec).decode() 106 + 107 + def plc_sign(privkey: ec.EllipticCurvePrivateKey, op: dict) -> str: 108 + if "sig" in op: 109 + raise ValueError("op is already signed!") 110 + rawsig = raw_sign(privkey, cbrrr.encode_dag_cbor(op)) 111 + return base64.urlsafe_b64encode(rawsig).decode().rstrip("=")
+4 -2
test_data/devenv_test_setup.sh
··· 8 8 rm -rf ./data 9 9 10 10 millipds init millipds.test 11 + millipds config --pds_pfx=http://$PDS_HOST 11 12 12 - ./create_identity.sh $HANDLE http://$PDS_HOST $PLC_HOST 13 13 14 + # generates keys and publishes to PLC 15 + ./create_identity.sh $HANDLE http://$PDS_HOST $PLC_HOST 14 16 DID_PLC=$(cat "${HANDLE}_did.txt") 15 17 16 - millipds config --pds_pfx=http://$PDS_HOST 18 + # create the account using the generated identity 17 19 millipds account create $DID_PLC $HANDLE --unsafe_password="lol" --signing_key="${HANDLE}_repo_key.pem" 18 20 19 21 #millipds run