Merge branch 'remove-demo-chat' into 'main'
Remove demo code from this repo See merge request veilid/veilid!109
This commit is contained in:
		| @@ -1,225 +0,0 @@ | |||||||
| #!/usr/bin/env python |  | ||||||
|  |  | ||||||
| """A simple chat server using Veilid's DHT.""" |  | ||||||
|  |  | ||||||
| import argparse |  | ||||||
| import asyncio |  | ||||||
| import sys |  | ||||||
|  |  | ||||||
| import config |  | ||||||
|  |  | ||||||
| import veilid |  | ||||||
|  |  | ||||||
| QUIT = "QUIT" |  | ||||||
| NONCE_LENGTH = 24 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def noop_callback(*args, **kwargs): |  | ||||||
|     """In the real world, we'd use this to process interesting incoming events.""" |  | ||||||
|  |  | ||||||
|     return |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def chatter( |  | ||||||
|     router: veilid.api.RoutingContext, |  | ||||||
|     crypto_system: veilid.CryptoSystem, |  | ||||||
|     key: veilid.TypedKey, |  | ||||||
|     secret: veilid.SharedSecret, |  | ||||||
|     send_subkey: veilid.ValueSubkey, |  | ||||||
|     recv_subkey: veilid.ValueSubkey, |  | ||||||
| ): |  | ||||||
|     """Read input, write it to the DHT, and print the response from the DHT.""" |  | ||||||
|  |  | ||||||
|     last_seq = -1 |  | ||||||
|  |  | ||||||
|     async def encrypt(cleartext: str) -> bytes: |  | ||||||
|         """Encrypt the message with the shared secret and a random nonce.""" |  | ||||||
|  |  | ||||||
|         nonce = await crypto_system.random_nonce() |  | ||||||
|         encrypted = await crypto_system.crypt_no_auth(cleartext.encode(), nonce, secret) |  | ||||||
|         return nonce.to_bytes() + encrypted |  | ||||||
|  |  | ||||||
|     async def decrypt(payload: bytes) -> str: |  | ||||||
|         """Decrypt the payload with the shared secret and the payload's nonce.""" |  | ||||||
|  |  | ||||||
|         nonce = veilid.Nonce.from_bytes(payload[:NONCE_LENGTH]) |  | ||||||
|         encrypted = payload[NONCE_LENGTH:] |  | ||||||
|         cleartext = await crypto_system.crypt_no_auth(encrypted, nonce, secret) |  | ||||||
|         return cleartext.decode() |  | ||||||
|  |  | ||||||
|     # Prime the pumps. Especially when starting the conversation, this |  | ||||||
|     # causes the DHT key to propagate to the network. |  | ||||||
|     await router.set_dht_value(key, send_subkey, await encrypt("Hello from the world!")) |  | ||||||
|  |  | ||||||
|     while True: |  | ||||||
|         try: |  | ||||||
|             msg = input("SEND> ") |  | ||||||
|         except EOFError: |  | ||||||
|             # Cat got your tongue? Hang up. |  | ||||||
|             print("Closing the chat.") |  | ||||||
|             await router.set_dht_value(key, send_subkey, await encrypt(QUIT)) |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         # Write the input message to the DHT key. |  | ||||||
|         await router.set_dht_value(key, send_subkey, await encrypt(msg)) |  | ||||||
|  |  | ||||||
|         # In the real world, don't do this. People may tease you for it. |  | ||||||
|         # This is meant to be easy to understand for demonstration |  | ||||||
|         # purposes, not a great pattern. Instead, you'd want to use the |  | ||||||
|         # callback function to handle events asynchronously. |  | ||||||
|         while True: |  | ||||||
|             # Try to get an updated version of the receiving subkey. |  | ||||||
|             resp = await router.get_dht_value(key, recv_subkey, True) |  | ||||||
|             if resp is None: |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             # If the other party hasn't sent a newer message, try again. |  | ||||||
|             if resp.seq == last_seq: |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             msg = await decrypt(resp.data) |  | ||||||
|             if msg == QUIT: |  | ||||||
|                 print("Other end closed the chat.") |  | ||||||
|                 return |  | ||||||
|  |  | ||||||
|             print(f"RECV< {msg}") |  | ||||||
|             last_seq = resp.seq |  | ||||||
|             break |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def start(host: str, port: int, name: str): |  | ||||||
|     """Begin a conversation with a friend.""" |  | ||||||
|  |  | ||||||
|     conn = await veilid.json_api_connect(host, port, noop_callback) |  | ||||||
|  |  | ||||||
|     keys = config.read_keys() |  | ||||||
|     my_keypair = keys["self"] |  | ||||||
|     their_key = keys["peers"][name] |  | ||||||
|  |  | ||||||
|     members = [ |  | ||||||
|         veilid.DHTSchemaSMPLMember(my_keypair.key(), 1), |  | ||||||
|         veilid.DHTSchemaSMPLMember(their_key, 1), |  | ||||||
|     ] |  | ||||||
|  |  | ||||||
|     router = await (await conn.new_routing_context()).with_privacy() |  | ||||||
|     crypto_system = await conn.get_crypto_system(veilid.CryptoKind.CRYPTO_KIND_VLD0) |  | ||||||
|     async with crypto_system, router: |  | ||||||
|         secret = await crypto_system.cached_dh(their_key, my_keypair.secret()) |  | ||||||
|  |  | ||||||
|         record = await router.create_dht_record(veilid.DHTSchema.smpl(0, members)) |  | ||||||
|         print(f"New chat key: {record.key}") |  | ||||||
|         print("Give that to your friend!") |  | ||||||
|  |  | ||||||
|         # Close this key first. We'll reopen it for writing with our saved key. |  | ||||||
|         await router.close_dht_record(record.key) |  | ||||||
|  |  | ||||||
|         await router.open_dht_record(record.key, my_keypair) |  | ||||||
|  |  | ||||||
|         try: |  | ||||||
|             # Write to the 1st subkey and read from the 2nd. |  | ||||||
|             await chatter(router, crypto_system, record.key, secret, 0, 1) |  | ||||||
|         finally: |  | ||||||
|             await router.close_dht_record(record.key) |  | ||||||
|             await router.delete_dht_record(record.key) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def respond(host: str, port: int, name: str, key: str): |  | ||||||
|     """Reply to a friend's chat.""" |  | ||||||
|  |  | ||||||
|     conn = await veilid.json_api_connect(host, port, noop_callback) |  | ||||||
|  |  | ||||||
|     keys = config.read_keys() |  | ||||||
|     my_keypair = keys["self"] |  | ||||||
|     their_key = keys["peers"][name] |  | ||||||
|  |  | ||||||
|     router = await (await conn.new_routing_context()).with_privacy() |  | ||||||
|     crypto_system = await conn.get_crypto_system(veilid.CryptoKind.CRYPTO_KIND_VLD0) |  | ||||||
|     async with crypto_system, router: |  | ||||||
|         secret = await crypto_system.cached_dh(their_key, my_keypair.secret()) |  | ||||||
|  |  | ||||||
|         await router.open_dht_record(key, my_keypair) |  | ||||||
|  |  | ||||||
|         # As the responder, we're writing to the 2nd subkey and reading from the 1st. |  | ||||||
|         await chatter(router, crypto_system, key, secret, 1, 0) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def keygen(host: str, port: int): |  | ||||||
|     """Generate a keypair.""" |  | ||||||
|  |  | ||||||
|     conn = await veilid.json_api_connect(host, port, noop_callback) |  | ||||||
|  |  | ||||||
|     crypto_system = await conn.get_crypto_system(veilid.CryptoKind.CRYPTO_KIND_VLD0) |  | ||||||
|     async with crypto_system: |  | ||||||
|         my_keypair = await crypto_system.generate_key_pair() |  | ||||||
|  |  | ||||||
|     keys = config.read_keys() |  | ||||||
|     if keys["self"]: |  | ||||||
|         print("You already have a keypair.") |  | ||||||
|         sys.exit(1) |  | ||||||
|  |  | ||||||
|     keys["self"] = my_keypair |  | ||||||
|     config.write_keys(keys) |  | ||||||
|  |  | ||||||
|     print(f"Your new public key is {my_keypair.key()}. Share it with your friends!") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def add_friend(host: str, port: int, name: str, pubkey: str): |  | ||||||
|     """Add a friend's public key.""" |  | ||||||
|  |  | ||||||
|     keys = config.read_keys() |  | ||||||
|     keys["peers"][name] = pubkey |  | ||||||
|     config.write_keys(keys) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| async def clean(host: str, port: int, key: str): |  | ||||||
|     """Delete a DHT key.""" |  | ||||||
|  |  | ||||||
|     conn = await veilid.json_api_connect(host, port, noop_callback) |  | ||||||
|  |  | ||||||
|     router = await (await conn.new_routing_context()).with_privacy() |  | ||||||
|     async with router: |  | ||||||
|         await router.close_dht_record(key) |  | ||||||
|         await router.delete_dht_record(key) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def handle_command_line(arglist: list[str]): |  | ||||||
|     """Process the command line. |  | ||||||
|  |  | ||||||
|     This isn't the interesting part.""" |  | ||||||
|  |  | ||||||
|     parser = argparse.ArgumentParser(description="Veilid chat demonstration") |  | ||||||
|     parser.add_argument("--host", default="localhost", help="Address of the Veilid server host.") |  | ||||||
|     parser.add_argument("--port", type=int, default=5959, help="Port of the Veilid server.") |  | ||||||
|  |  | ||||||
|     subparsers = parser.add_subparsers(required=True) |  | ||||||
|  |  | ||||||
|     cmd_start = subparsers.add_parser("start", help=start.__doc__) |  | ||||||
|     cmd_start.add_argument("name", help="Your friend's name") |  | ||||||
|     cmd_start.set_defaults(func=start) |  | ||||||
|  |  | ||||||
|     cmd_respond = subparsers.add_parser("respond", help=respond.__doc__) |  | ||||||
|     cmd_respond.add_argument("name", help="Your friend's name") |  | ||||||
|     cmd_respond.add_argument("key", help="The chat's DHT key") |  | ||||||
|     cmd_respond.set_defaults(func=respond) |  | ||||||
|  |  | ||||||
|     cmd_keygen = subparsers.add_parser("keygen", help=keygen.__doc__) |  | ||||||
|     cmd_keygen.set_defaults(func=keygen) |  | ||||||
|  |  | ||||||
|     cmd_add_friend = subparsers.add_parser("add-friend", help=add_friend.__doc__) |  | ||||||
|     cmd_add_friend.add_argument("name", help="Your friend's name") |  | ||||||
|     cmd_add_friend.add_argument("pubkey", help="Your friend's public key") |  | ||||||
|     cmd_add_friend.set_defaults(func=add_friend) |  | ||||||
|  |  | ||||||
|     cmd_clean = subparsers.add_parser("clean", help=clean.__doc__) |  | ||||||
|     cmd_clean.add_argument("key", help="DHT key to delete") |  | ||||||
|     cmd_clean.set_defaults(func=clean) |  | ||||||
|  |  | ||||||
|     args = parser.parse_args(arglist) |  | ||||||
|     kwargs = args.__dict__ |  | ||||||
|     func = kwargs.pop("func") |  | ||||||
|  |  | ||||||
|     asyncio.run(func(**kwargs)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     handle_command_line(sys.argv[1:]) |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| """Load and save configuration.""" |  | ||||||
|  |  | ||||||
| import json |  | ||||||
| from pathlib import Path |  | ||||||
|  |  | ||||||
| import veilid |  | ||||||
|  |  | ||||||
| KEYFILE = Path(".demokeys") |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def read_keys() -> dict: |  | ||||||
|     """Load the stored keys from disk.""" |  | ||||||
|  |  | ||||||
|     try: |  | ||||||
|         raw = KEYFILE.read_text() |  | ||||||
|     except FileNotFoundError: |  | ||||||
|         return { |  | ||||||
|             "self": None, |  | ||||||
|             "peers": {}, |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     keys = json.loads(raw) |  | ||||||
|     if keys["self"] is not None: |  | ||||||
|         keys["self"] = veilid.KeyPair(keys["self"]) |  | ||||||
|     for name, pubkey in keys["peers"].items(): |  | ||||||
|         keys["peers"][name] = veilid.PublicKey(pubkey) |  | ||||||
|     return keys |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def write_keys(keydata: dict): |  | ||||||
|     """Save the keys to disk.""" |  | ||||||
|  |  | ||||||
|     KEYFILE.write_text(json.dumps(keydata, indent=2)) |  | ||||||
		Reference in New Issue
	
	Block a user