diff --git a/app.py b/app.py new file mode 100644 index 0000000..0986775 --- /dev/null +++ b/app.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +import asyncio +import getpass +import json +import os +import sys + +import aiofiles + +from nio import AsyncClient, LoginResponse + +CONFIG_FILE = "credentials.json" + +# Check out main() below to see how it's done. + + +def write_details_to_disk(resp: LoginResponse, homeserver) -> None: + """Writes the required login details to disk so we can log in later without + using a password. + + Arguments: + resp {LoginResponse} -- the successful client login response. + homeserver -- URL of homeserver, e.g. "https://matrix.example.org" + """ + # open the config file in write-mode + with open(CONFIG_FILE, "w") as f: + # write the login details to disk + json.dump( + { + "homeserver": homeserver, # e.g. "https://matrix.example.org" + "user_id": resp.user_id, # e.g. "@user:example.org" + "device_id": resp.device_id, # device ID, 10 uppercase letters + "access_token": resp.access_token, # cryptogr. access token + }, + f, + ) + + +async def main() -> None: + # If there are no previously-saved credentials, we'll use the password + if not os.path.exists(CONFIG_FILE): + print( + "First time use. Did not find credential file. Asking for " + "homeserver, user, and password to create credential file." + ) + homeserver = "https://matrix.example.org" + homeserver = input(f"Enter your homeserver URL: [{homeserver}] ") + + if not (homeserver.startswith("https://") or homeserver.startswith("http://")): + homeserver = "https://" + homeserver + + user_id = "@user:example.org" + user_id = input(f"Enter your full user ID: [{user_id}] ") + + device_name = "matrix-nio" + device_name = input(f"Choose a name for this device: [{device_name}] ") + + client = AsyncClient(homeserver, user_id) + pw = getpass.getpass() + + resp = await client.login(pw, device_name=device_name) + + # check that we logged in successfully + if isinstance(resp, LoginResponse): + write_details_to_disk(resp, homeserver) + else: + print(f'homeserver = "{homeserver}"; user = "{user_id}"') + print(f"Failed to log in: {resp}") + sys.exit(1) + + print( + "Logged in using a password. Credentials were stored.", + "Try running the script again to login with credentials.", + ) + + # Otherwise the config file exists, so we'll use the stored credentials + else: + # open the file in read-only mode + async with aiofiles.open(CONFIG_FILE, "r") as f: + contents = await f.read() + config = json.loads(contents) + client = AsyncClient(config["homeserver"]) + + client.access_token = config["access_token"] + client.user_id = config["user_id"] + client.device_id = config["device_id"] + + # Now we can send messages as the user + room_id = "!myfavouriteroomid:example.org" + room_id = input(f"Enter room id for test message: [{room_id}] ") + + await client.room_send( + room_id, + message_type="m.room.message", + content={"msgtype": "m.text", "body": "Hello world!"}, + ) + print("Logged in using stored credentials. Sent a test message.") + + # Either way we're logged in here, too + await client.close() + + +asyncio.run(main())