generated from anoadragon453/nio-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from half-duplex/async-tokens
Async and data integrity protections from half-duplex
- Loading branch information
Showing
14 changed files
with
275 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[flake8] | ||
max-line-length = 99 | ||
import-order-style = google | ||
exclude = | ||
env/* | ||
venv/* | ||
accept-encodings = utf-8 | ||
ignore = E203 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: Python lint | ||
|
||
on: [push, pull_request] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: [3.8] | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install -r requirements-dev.txt | ||
- name: Lint with black | ||
run: | | ||
black . --check | ||
- name: Lint with flake8 | ||
run: | | ||
# stop the build if there are Python syntax errors or undefined names | ||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | ||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide | ||
flake8 . --count --exit-zero --statistics |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,54 @@ | ||
from nio import Api | ||
# coding=utf-8 | ||
|
||
from hashlib import sha256 | ||
def valid_token(token, tokens,sender): | ||
import logging | ||
|
||
from nio import Api | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def valid_token(token, tokens, sender): | ||
h = sha256() | ||
h.update(token.encode("utf-8")) | ||
msg = h.hexdigest() | ||
if msg in tokens: | ||
if tokens[msg] == 'unused': | ||
if tokens[msg] == "unused": | ||
return True, msg | ||
elif tokens[msg] == sender: | ||
return True, msg | ||
return False, "" | ||
return False, msg | ||
|
||
|
||
async def community_invite(client, group, sender):# | ||
async def community_invite(client, group, sender): # | ||
if not group: | ||
return | ||
path = "groups/{}/admin/users/invite/{}".format(group,sender) | ||
data = {"user_id":sender} | ||
path = "groups/{}/admin/users/invite/{}".format(group, sender) | ||
data = {"user_id": sender} | ||
query_parameters = {"access_token": client.access_token} | ||
path = Api._build_path(path, query_parameters) | ||
print(path) | ||
await client.send("PUT", | ||
path, | ||
Api.to_json(data), | ||
headers = {"Content-Type": "application/json"} | ||
) | ||
logging.debug("community_invite path: %r", path) | ||
await client.send( | ||
"PUT", path, Api.to_json(data), headers={"Content-Type": "application/json"} | ||
) | ||
return | ||
|
||
|
||
def is_admin(user): | ||
user = str(user) | ||
print(user) | ||
logging.debug("is_admin? %s", user) | ||
try: | ||
f = open("admin.csv", "rt") | ||
for nick in f.readlines(): | ||
print(nick) | ||
logging.debug("is_admin line: %s", nick) | ||
if user == nick.rstrip(): | ||
f.close() | ||
return True | ||
f.close() | ||
except FileNotFoundError: | ||
print("no admin.csv") | ||
logging.error("No admin.csv") | ||
return False | ||
|
||
|
||
def get_alias(roomid): | ||
return roomid |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,21 @@ | ||
# coding=utf-8 | ||
|
||
from asyncio import Lock | ||
import csv | ||
import logging | ||
from os import fsync, rename | ||
|
||
from bot_actions import community_invite, is_admin, valid_token | ||
from chat_functions import send_text_to_room | ||
from bot_actions import valid_token, community_invite, is_admin, get_alias | ||
from nio import RoomResolveAliasResponse | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
_attendee_token_lock = Lock() | ||
_presenter_token_lock = Lock() | ||
_volunteer_token_lock = Lock() | ||
|
||
|
||
class Command(object): | ||
def __init__(self, client, store, config, command, room, event): | ||
"""A command made by a user | ||
|
@@ -27,9 +41,9 @@ def __init__(self, client, store, config, command, room, event): | |
self.event = event | ||
self.args = self.command.split()[1:] | ||
|
||
|
||
async def process(self): | ||
"""Process the command""" | ||
logging.debug("Got command from %s: %r", self.event.sender, self.command) | ||
trigger = self.command.lower() | ||
if trigger.startswith("help"): | ||
await self._show_help() | ||
|
@@ -38,7 +52,7 @@ async def process(self): | |
elif trigger.startswith("ticket"): | ||
await self._process_request("attendee") | ||
elif trigger.startswith("volunteer"): | ||
#await self._volunteer_request() | ||
# await self._volunteer_request() | ||
await self._process_request("volunteer") | ||
elif trigger.startswith("presenter"): | ||
await self._process_request("presenter") | ||
|
@@ -52,98 +66,144 @@ async def process(self): | |
|
||
async def _process_request(self, ticket_type): | ||
"""!h $ticket_type $token""" | ||
if not self.args: | ||
response = "You need to add your token after {}".format(self.command) | ||
if not self.args: | ||
response = ( | ||
"Add the ticket code from your email after the command, like this: \n" | ||
f"`{self.command} a1b2c3d4e5...`" | ||
) | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
return | ||
print("args are:" + " ".join([str(x) for x in self.args])) | ||
print("from: " + self.event.sender) | ||
logging.debug("ticket cmd from %s for %s", self.event.sender, ticket_type) | ||
token = str(self.args[0]) | ||
if len(token) != 64: | ||
response = "Token must be 64 characters, check your ticket again or if you have trouble, please send an email to [email protected]" | ||
response = ( | ||
"Token must be 64 characters, check your ticket again or if you " | ||
"have trouble, please send an email to [email protected]" | ||
) | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
return | ||
lock = _attendee_token_lock | ||
tokens = self.config.tokens | ||
rooms = self.config.rooms | ||
group = self.config.community | ||
filename = "tokens.csv" | ||
if ticket_type == "presenter": | ||
lock = _presenter_token_lock | ||
tokens = self.config.presenter_tokens | ||
rooms = self.config.presenter_rooms | ||
group = self.config.presenter_community | ||
filename = "presenters.csv" | ||
print("presenter") | ||
elif ticket_type == "volunteer": | ||
lock = _volunteer_token_lock | ||
tokens = self.config.volunteer_tokens | ||
rooms = self.config.volunteer_rooms | ||
group = self.config.volunteer_community | ||
filename = "volunteers.csv" | ||
|
||
valid, h = valid_token(token, tokens,self.event.sender) | ||
if valid: | ||
response = "Verified ticket. You should now be invited to the {} rooms.".format(ticket_type) | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
print(rooms) | ||
for r in rooms: | ||
await self.client.room_invite(r, self.event.sender) | ||
if tokens[h] == "unused": | ||
await send_text_to_room(self.client, self.room.room_id, "Inviting you to the HOPE community...") | ||
# Make sure other tasks don't interfere with our token[] manipulation or writing | ||
async with lock: | ||
valid, h = valid_token(token, tokens, self.event.sender) | ||
if valid: | ||
response = ( | ||
"Verified ticket. You should now be invited to the HOPE " | ||
f"{ticket_type} chat rooms and community." | ||
) | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
logging.debug("Inviting %s to %s", self.event.sender, ",".join(rooms)) | ||
for r in rooms: | ||
await self.client.room_invite(r, self.event.sender) | ||
await community_invite(self.client, group, self.event.sender) | ||
tokens[h] = self.event.sender | ||
with open(filename, 'w') as f: | ||
for key in tokens.keys(): | ||
f.write("%s,%s\n"%(key,tokens[key])) | ||
return | ||
else: | ||
response = "This is not a valid token, check your ticket again or email [email protected]" | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
return | ||
|
||
if tokens[h] == "unused": | ||
tokens[h] = self.event.sender | ||
filename_temp = filename + ".atomic" | ||
with open(filename_temp, "w") as f: | ||
csv_writer = csv.writer(f) | ||
csv_writer.writerows(tokens.items()) | ||
f.flush() | ||
fsync(f.fileno()) | ||
rename(filename_temp, filename) | ||
|
||
return | ||
else: | ||
logging.info( | ||
"ticket invalid: %s: %s %s (%s)", | ||
self.event.sender, | ||
ticket_type, | ||
token, | ||
tokens.get(h, "<invalid>"), | ||
) | ||
# notify outside lock block | ||
response = ( | ||
"This is not a valid token, check your ticket again or " | ||
"email [email protected]" | ||
) | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
|
||
async def _volunteer_request(self): | ||
response = "Inviting you to the HOPE volunteer rooms..." | ||
await send_text_to_room(self.client, self.room.room_id, response) | ||
for r in self.config.volunteer_rooms: | ||
await self.client.room_invite(r, self.event.sender) | ||
await send_text_to_room(self.client, self.room.room_id, "Inviting you to the HOPE community") | ||
await community_invite(self.client, self.config.volunteer_community, self.event.sender) | ||
return | ||
await send_text_to_room( | ||
self.client, self.room.room_id, "Inviting you to the HOPE community" | ||
) | ||
await community_invite( | ||
self.client, self.config.volunteer_community, self.event.sender | ||
) | ||
|
||
async def _show_help(self): | ||
"""Show the help text""" | ||
if not self.args: | ||
text = ("Hello, I'm the HOPE CoreBot! To be invited to the official conference channels message me with `ticket <your-token-here>`. You can see more information (important for presenters) at https://wiki.hope.net/index.php?title=Conference_bot") | ||
text = ( | ||
"Hello, I'm the HOPE CoreBot! To be invited to the official " | ||
"conference channels message me with `ticket <your-token-here>`. " | ||
"You can find more information (important for presenters) on the " | ||
"[conference bot wiki](https://wiki.hope.net/index.php?title=Conference_bot)." | ||
) | ||
await send_text_to_room(self.client, self.room.room_id, text) | ||
return | ||
|
||
async def _the_planet(self): | ||
text = "HACK THE PLANET https://youtu.be/YV78vobCyIo?t=55" | ||
await send_text_to_room(self.client, self.room.room_id, text) | ||
return | ||
|
||
async def _trashing(self): | ||
text = """They\'re TRASHING our rights, man! They\'re | ||
TRASHING the flow of data! They\'re TRASHING! | ||
TRASHING! TRASHING! HACK THE PLANET! HACK | ||
THE PLANET!""" | ||
TRASHING the flow of data! They\'re TRASHING! | ||
TRASHING! TRASHING! HACK THE PLANET! HACK | ||
THE PLANET!""" | ||
await send_text_to_room(self.client, self.room.room_id, text) | ||
return | ||
|
||
async def _group(self): | ||
await send_text_to_room(self.client, self.room.room_id, "inviting to group") | ||
await community_invite(self.client, self.config, self.event.sender) | ||
|
||
async def _notice(self): | ||
print("notice") | ||
msg = "@room " + " ".join(map(str, self.args[1:])) | ||
logging.warning( | ||
"notice used by %s at %s to send: %r", | ||
self.event.sender, | ||
self.room.room_id, | ||
msg, | ||
) | ||
if len(self.args) < 2: | ||
await send_text_to_room(self.client, self.room.room_id, "notice args: <room-alias\> <strings\>,,,") | ||
await send_text_to_room( | ||
self.client, | ||
self.room.room_id, | ||
"notice args: <room-alias\\> <strings\\>,,,", | ||
) | ||
return | ||
resp = await self.client.room_resolve_alias(self.args[0]) | ||
if not isinstance(resp, RoomResolveAliasResponse): | ||
print("bad room alias") | ||
logging.info("notice: bad room alias %s", self.args[0]) | ||
await send_text_to_room( | ||
self.client, self.room.room_id, "Invalid room alias" | ||
) | ||
return | ||
room_id = resp.room_id | ||
msg = "@room " + ' '.join(map(str, self.args[1:])) | ||
print("send {} to {}".format(msg,room_id)) | ||
await send_text_to_room(self.client, room_id, msg) | ||
return | ||
await send_text_to_room(self.client, self.room.room_id, "Sent") | ||
|
||
async def _invite(self): | ||
#invite user to set of rooms | ||
return | ||
# invite user to set of rooms | ||
pass |
Oops, something went wrong.