66 lines
2.1 KiB
Python
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
|