Files
quantumtunnel/demo/server.py
T
2026-10-07 03:07:34 +00:00

66 lines
2.1 KiB
Python

"""Demo server: python demo/server.py
Accepts WebSocket clients on ws://127.0.0.1:8765, runs the handshake as
responder (identifying each caller by trying its key store against
msg1), prints the verification digest for comparison, then echoes
messages back. Ctrl-C to stop.
"""
import asyncio
from common import key_store, psk, save_store, setup_logging
from websockets import serve
from websockets.exceptions import ConnectionClosed
from quantumpipe import ProtocolError, SecSocket, Verification, sas
log = setup_logging("server")
psk() # eager: create demo/psk before we listen (avoids a creation race)
async def show_digest(v: Verification) -> None:
# returning None answers with the app default: proceed unverified --
# the digest stays exposed (sock.session.verification) for an optional
# comparison, confirmed later via sock.session.confirm; answering False
# instead would delete the credential
log.info("compare these emojis with the client:\n%s", sas.format(v.sas))
async def handle(ws) -> None:
# per connection: re-read the store; the handshake mutates it in
# place (rotation, flag, burn, delete) and we persist after
store = key_store("server")
sock = SecSocket(ws, store, handlers={Verification: show_digest})
try:
await sock.accept()
except (ProtocolError, ConnectionClosed) as e:
log.info("handshake failed: %s", e)
return
finally:
save_store("server", store)
log.info(
"handshake done (%s, verified=%s), echoing",
sock.session.state,
sock.session.verified,
)
try:
while True:
msg = await sock.receive()
log.info("received %r", msg)
await sock.send(f"echo: {msg}")
except ConnectionClosed:
log.info("client disconnected")
async def main() -> None:
async with serve(handle, "127.0.0.1", 8765):
log.info("listening on ws://127.0.0.1:8765")
await asyncio.Future() # serve forever
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
pass