Skip to content
This repository was archived by the owner on May 22, 2024. It is now read-only.

Commit 5fff9d0

Browse files
author
KrazyKirby99999
authored
Merge pull request #70 from KrazyKirby99999/access_token
Access token login support added.
2 parents b658527 + 0d3355a commit 5fff9d0

File tree

4 files changed

+71
-27
lines changed

4 files changed

+71
-27
lines changed

doc/manual/creds.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,21 @@ creds = botlib.Creds(
1414
or
1515
```python
1616
creds = botlib.Creds(
17-
homeserver="https://example.org",
18-
login_token="MDA..gZ2"
17+
homeserver="https://example.org",
18+
username="username",
19+
login_token="MDA..gZ2",
1920
session_stored_file="session.txt"
2021
)
2122
```
22-
The homeserver argument is always required. The username, and password arguments are also required unless the login_token argument is used. The keyword "login_token" must be specified when the login_token argument is used. Although the login_token can only be used to authenticate with the homeserver once, it is required in every run of the bot in order to encrypt/decrypt the session data such as the access_token. If the login_token is used and the session_stored_file argument is set to `None`, then the bot will only be able to run once per login_token. The session_stored_file argument is optional and allows for specific data relating to each session such as the access token and the device name to be preserved across each run of the bot.
23+
or
24+
```python
25+
creds = botlib.Creds(
26+
homeserver="https://example.org",
27+
username="username",
28+
access_token="syt_c2...DTJ",
29+
session_stored_file="session.txt"
30+
)
31+
```
32+
The homeserver and username arguments are always required. The password argument may be replaced by either the login_token argument or the access_token argument. The login_token is used with handling SSO logins (See the [Matrix Docs](https://matrix.org/docs/guides/sso-for-client-developers#handling-sso)). The access_token is normally generated after using a different login method with another client.
33+
34+
The optional session_stored_file argument is the location of a file used by the bot to store session information such as the generated access token and device name. A login_token can only be used to authenticate once, so setting the session_stored_file argument to "" will require you to enter a new SSO token each time the program is run.

simplematrixbotlib/api.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import mimetypes
66
import os
77
import markdown
8-
8+
import aiohttp
9+
import ast
910
from nio.responses import UploadResponse
11+
import nio
1012

1113

1214
class Api:
@@ -37,30 +39,36 @@ async def login(self):
3739
3840
"""
3941

40-
self.creds.session_read_file()
42+
if not self.creds.homeserver:
43+
raise ValueError("Missing homeserver")
44+
if not self.creds.username:
45+
raise ValueError("Missing Username")
46+
if not (self.creds.password or self.creds.login_token or self.creds.access_token):
47+
raise ValueError("Missing password, login token, access token. Either password, login token or access token must be provided")
4148

42-
self.async_client = AsyncClient(self.creds.homeserver,
43-
self.creds.username)
49+
self.async_client = AsyncClient(homeserver=self.creds.homeserver, user=self.creds.username, device_id=self.creds.device_id)
4450

45-
if self.creds.device_id:
46-
self.async_client.device_id = self.creds.device_id
51+
if self.creds.password:
52+
resp = await self.async_client.login(password=self.creds.password, device_name=self.creds.device_name)
4753

48-
if self.creds.password or self.creds.login_token:
49-
response = await self.async_client.login(
50-
password=self.creds.password,
51-
device_name='Bot Client built with Simple-Matrix-Bot-Lib',
52-
token=self.creds.login_token)
53-
print(response)
54+
elif self.creds.access_token:
55+
self.async_client.access_token = self.creds.access_token
5456

55-
self.creds.device_id = response.device_id
56-
self.creds.access_token = response.access_token
57+
async with aiohttp.ClientSession() as session:
58+
async with session.get(f'https://matrix.org/_matrix/client/r0/account/whoami?access_token={self.creds.access_token}') as response:
59+
device_id = ast.literal_eval((await response.text()).replace(":false,", ":\"false\","))['device_id']
60+
user_id = ast.literal_eval((await response.text()).replace(":false,", ":\"false\","))['user_id']
61+
62+
self.async_client.device_id, self.creds.device_id = device_id, device_id
63+
self.async_client.user_id, self.creds.user_id = user_id, user_id
64+
resp = None
5765

58-
else:
59-
self.async_client.access_token = self.creds.access_token
60-
self.async_client.user_id = f"@{self.creds.username}:{self.creds.homeserver}"
61-
self.async_client.device_id = self.creds.device_id
66+
elif self.creds.login_token:
67+
resp = await self.async_client.login(token=self.creds.login_token, device_name=self.creds.device_name)
68+
69+
if isinstance(resp, nio.responses.LoginError):
70+
raise Exception(resp)
6271

63-
self.creds.session_write_file()
6472

6573
async def send_text_message(self, room_id, message):
6674
"""
@@ -159,3 +167,5 @@ async def send_markdown_message(self, room_id, message):
159167
"formatted_body":
160168
markdown.markdown(message)
161169
})
170+
171+

simplematrixbotlib/auth.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def __init__(self,
2424
username=None,
2525
password=None,
2626
login_token=None,
27+
access_token=None,
2728
session_stored_file='session.txt'):
2829
"""
2930
Initializes the simplematrixbotlib.Creds class.
@@ -37,10 +38,13 @@ def __init__(self,
3738
The username for the bot to connect as. This is neccesary if password is used instead of login_token.
3839
3940
password : str, optional
40-
The password for the bot to connect with. Can be used instead of login_token. Either the login_token or password must be provided.
41+
The password for the bot to connect with. Can be used instead of login_token. One of the password, login_token, or access_token must be provided.
4142
4243
login_token : str, optional
43-
The login_token for the bot to connect with. Can be used instead of password. Either the login_token or password must be provided.
44+
The login_token for the bot to connect with. Can be used instead of password. One of the password, login_token, or access_token must be provided.
45+
46+
access_token : str, optional
47+
The access_token for the bot to connect with. Can be used instead of password. One of the password, login_token, or access_token must be provided.
4448
4549
session_stored_file : str, optional
4650
Location for the bot to read and write device_id and access_token. The data within this file is encrypted and decrypted with the password parameter using the cryptography package. If set to None, session data will not be saved to file.
@@ -51,11 +55,19 @@ def __init__(self,
5155
self.username = username
5256
self.password = password
5357
self.login_token = login_token
58+
self.access_token = access_token
5459
self._session_stored_file = session_stored_file
60+
self.device_name = "Bot Client using Simple-Matrix-Bot-Lib"
61+
self.device_id = ""
62+
5563
if self.password:
5664
self._key = fw.key_from_pass(self.password)
57-
else:
65+
elif self.login_token:
5866
self._key = fw.key_from_pass(self.login_token)
67+
elif self.access_token:
68+
self._key = fw.key_from_pass(self.access_token)
69+
else:
70+
raise ValueError("password or login_token or access_token is required")
5971

6072
def session_read_file(self):
6173
"""
@@ -85,7 +97,6 @@ def session_read_file(self):
8597

8698
if not file_exists:
8799
self.device_id = None
88-
self.access_token = None
89100

90101
def session_write_file(self):
91102
"""

simplematrixbotlib/bot.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import simplematrixbotlib as botlib
3+
from nio import SyncResponse
34

45

56
class Bot:
@@ -29,12 +30,22 @@ def __init__(self, creds):
2930
self.listener = botlib.Listener(self)
3031

3132
async def main(self):
33+
34+
self.creds.session_read_file()
35+
3236
await self.api.login()
37+
3338
self.async_client = self.api.async_client
3439

35-
await self.async_client.sync(timeout=65536,
40+
41+
resp = await self.async_client.sync(timeout=65536,
3642
full_state=False) #Ignore prior messages
3743

44+
if isinstance(resp, SyncResponse):
45+
print(f"Connected to {self.async_client.homeserver} as {self.async_client.user_id} ({self.async_client.device_id})")
46+
47+
self.creds.session_write_file()
48+
3849
self.callbacks = botlib.Callbacks(self.async_client, self)
3950
await self.callbacks.setup_callbacks()
4051

0 commit comments

Comments
 (0)