v0.0.28 - Finalize Feather TinyUSB migration and remove cardputer artifacts
This commit is contained in:
136
examples/feather_get_public_key.py
Normal file
136
examples/feather_get_public_key.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
|
||||
import serial
|
||||
from coincurve import PrivateKey
|
||||
|
||||
|
||||
def read_exact(ser: serial.Serial, n: int, timeout_s: float = 8.0) -> bytes:
|
||||
end = time.time() + timeout_s
|
||||
out = bytearray()
|
||||
while len(out) < n and time.time() < end:
|
||||
chunk = ser.read(n - len(out))
|
||||
if chunk:
|
||||
out.extend(chunk)
|
||||
continue
|
||||
time.sleep(0.005)
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def recv_frame(ser: serial.Serial, timeout_s: float = 10.0) -> bytes:
|
||||
end = time.time() + timeout_s
|
||||
window = bytearray()
|
||||
|
||||
while time.time() < end:
|
||||
b = ser.read(1)
|
||||
if not b:
|
||||
time.sleep(0.005)
|
||||
continue
|
||||
window.extend(b)
|
||||
if len(window) > 4:
|
||||
window.pop(0)
|
||||
if len(window) < 4:
|
||||
continue
|
||||
(n,) = struct.unpack(">I", bytes(window))
|
||||
# Keep this cap small to avoid getting stuck on false headers in stream noise.
|
||||
if n == 0 or n > 64 * 1024:
|
||||
continue
|
||||
body = read_exact(ser, n, timeout_s=max(0.2, end - time.time()))
|
||||
if len(body) != n:
|
||||
continue
|
||||
if body[:1] not in (b"{", b"["):
|
||||
continue
|
||||
try:
|
||||
json.loads(body.decode("utf-8", errors="strict"))
|
||||
except Exception:
|
||||
continue
|
||||
return body
|
||||
|
||||
return b""
|
||||
|
||||
|
||||
def build_auth_envelope(method: str, params, caller_priv: bytes, label: str = "py-cli") -> dict:
|
||||
body_json = json.dumps(params, separators=(",", ":")).encode("utf-8")
|
||||
body_hash = hashlib.sha256(body_json).hexdigest()
|
||||
|
||||
sk = PrivateKey(caller_priv)
|
||||
caller_pub_x = sk.public_key.format(compressed=True)[1:].hex()
|
||||
|
||||
created_at = int(time.time())
|
||||
tags = [
|
||||
["nsigner_rpc", "1"],
|
||||
["nsigner_method", method],
|
||||
["nsigner_body_hash", body_hash],
|
||||
]
|
||||
serialized = json.dumps(
|
||||
[0, caller_pub_x, created_at, 27235, tags, label],
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
).encode("utf-8")
|
||||
event_id = hashlib.sha256(serialized).hexdigest()
|
||||
sig = sk.sign_schnorr(bytes.fromhex(event_id), aux_randomness=b"\x00" * 32).hex()
|
||||
|
||||
return {
|
||||
"id": event_id,
|
||||
"pubkey": caller_pub_x,
|
||||
"created_at": created_at,
|
||||
"kind": 27235,
|
||||
"tags": tags,
|
||||
"content": label,
|
||||
"sig": sig,
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
port = sys.argv[1] if len(sys.argv) > 1 else "/dev/ttyACM0"
|
||||
|
||||
caller_priv = bytes(range(1, 33))
|
||||
params = []
|
||||
|
||||
req = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": "1",
|
||||
"method": "get_public_key",
|
||||
"params": params,
|
||||
"auth": build_auth_envelope("get_public_key", params, caller_priv),
|
||||
}
|
||||
body = json.dumps(req, separators=(",", ":")).encode("utf-8")
|
||||
frame = struct.pack(">I", len(body)) + body
|
||||
|
||||
ser = serial.Serial()
|
||||
ser.port = port
|
||||
ser.baudrate = 115200
|
||||
ser.timeout = 0.2
|
||||
ser.rtscts = False
|
||||
ser.dsrdtr = False
|
||||
# Set modem-control lines before open to avoid auto-reset pulses.
|
||||
ser.dtr = False
|
||||
ser.rts = False
|
||||
|
||||
with ser:
|
||||
# Let the board settle if OS still caused a reconnect.
|
||||
time.sleep(3.0)
|
||||
|
||||
for attempt in range(1, 4):
|
||||
ser.reset_input_buffer()
|
||||
ser.write(frame)
|
||||
ser.flush()
|
||||
|
||||
resp_body = recv_frame(ser, timeout_s=10.0)
|
||||
if resp_body:
|
||||
print(resp_body.decode("utf-8", errors="replace"))
|
||||
return 0
|
||||
|
||||
print(f"No framed response received (attempt {attempt}/3)")
|
||||
time.sleep(0.5)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user