2017-03-04 21:45:09 +00:00
|
|
|
import json
|
2024-12-15 23:04:17 +00:00
|
|
|
import yaml
|
2017-03-04 21:45:09 +00:00
|
|
|
import requests
|
|
|
|
import logging
|
2024-12-15 23:04:17 +00:00
|
|
|
import logging.config
|
2017-07-28 23:16:36 +00:00
|
|
|
import re
|
2018-01-10 00:28:53 +00:00
|
|
|
import pnutpy
|
2020-05-08 15:36:03 +00:00
|
|
|
import textwrap
|
|
|
|
import time
|
2024-12-15 23:04:17 +00:00
|
|
|
import os
|
|
|
|
|
|
|
|
from mautrix.client import ClientAPI
|
|
|
|
from mautrix.types import *
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
from models import Avatars, Rooms, Events, Users, DirectRooms, ControlRooms
|
2019-01-04 03:49:38 +00:00
|
|
|
from database import db_session
|
|
|
|
from sqlalchemy import and_
|
2017-03-04 21:45:09 +00:00
|
|
|
from flask import Flask, jsonify, request, abort
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2017-03-04 21:45:09 +00:00
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
@app.errorhandler(404)
|
|
|
|
def not_found(error):
|
2024-12-15 23:04:17 +00:00
|
|
|
return jsonify({'errcode':'PNUT_NOT_FOUND'}), 404
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
@app.errorhandler(403)
|
|
|
|
def forbidden(error):
|
2024-12-15 23:04:17 +00:00
|
|
|
return jsonify({'errcode':'PNUT_FORBIDDEN'}), 403
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
@app.teardown_appcontext
|
|
|
|
def shutdown_session(exception=None):
|
|
|
|
db_session.remove()
|
|
|
|
|
2023-05-01 21:18:53 +00:00
|
|
|
@app.route("/_matrix/app/v1/rooms/<alias>")
|
2019-01-04 03:49:38 +00:00
|
|
|
@app.route("/rooms/<alias>")
|
2024-12-15 23:04:17 +00:00
|
|
|
async def query_alias(alias):
|
|
|
|
logging.debug("--- query alias ---")
|
2019-01-04 03:49:38 +00:00
|
|
|
alias_localpart = alias.split(":")[0][1:]
|
|
|
|
channel_id = int(alias_localpart.split('_')[1])
|
|
|
|
|
|
|
|
room = Rooms.query.filter(Rooms.pnut_chan == channel_id).one_or_none()
|
|
|
|
if room is not None:
|
|
|
|
abort(404)
|
|
|
|
|
|
|
|
token = app.config['MATRIX_PNUT_TOKEN']
|
|
|
|
pnutpy.api.add_authorization_token(token)
|
|
|
|
try:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug("---- getting the channel ----")
|
|
|
|
channel, meta = pnutpy.api.get_channel(channel_id,
|
|
|
|
include_channel_raw=1)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
if 'is_active' in channel and channel.is_active == False:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug("-channel isn't active-")
|
2019-01-04 03:49:38 +00:00
|
|
|
abort(404)
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
if 'io.pnut.core.chat-settings' in channel.raw:
|
|
|
|
for setting in channel.raw['io.pnut.core.chat-settings']:
|
|
|
|
if 'name' in setting:
|
|
|
|
name = setting['name']
|
|
|
|
else:
|
|
|
|
name = None
|
|
|
|
if 'description' in setting:
|
|
|
|
topic = setting['description']['text']
|
|
|
|
else:
|
|
|
|
topic = None
|
|
|
|
|
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2022-06-30 19:47:31 +00:00
|
|
|
if channel.acl.read.public:
|
2024-12-15 23:04:17 +00:00
|
|
|
visibility = RoomDirectoryVisibility.PUBLIC
|
|
|
|
preset = RoomCreatePreset.PUBLIC
|
2022-06-30 19:47:31 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
visibility = RoomDirectoryVisibility.PRIVATE
|
|
|
|
preset = RoomCreatePreset.PRIVATE
|
|
|
|
room_id = await matrix_api.create_room(alias_localpart,
|
|
|
|
visibility=visibility,
|
|
|
|
preset=preset,
|
|
|
|
name=name,
|
|
|
|
topic=topic)
|
|
|
|
|
|
|
|
if not channel.you_subscribed:
|
2019-01-04 03:49:38 +00:00
|
|
|
pnutpy.api.subscribe_channel(channel_id)
|
2024-12-15 23:04:17 +00:00
|
|
|
rr = Rooms(
|
|
|
|
room_id=room_id,
|
|
|
|
pnut_chan=channel_id,
|
|
|
|
portal=True
|
|
|
|
)
|
|
|
|
logging.debug(rr.room_id)
|
|
|
|
logging.debug(rr.pnut_chan)
|
|
|
|
db_session.add(rr)
|
|
|
|
db_session.commit()
|
2023-07-04 16:33:24 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
except pnutpy.errors.PnutPermissionDenied:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug("-permission denied-")
|
2021-03-20 13:26:33 +00:00
|
|
|
abort(401)
|
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
except Exception:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception("-couldn't get the pnut channel-")
|
2019-01-04 03:49:38 +00:00
|
|
|
abort(404)
|
2017-05-05 03:23:02 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
return jsonify({})
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2023-05-01 21:18:53 +00:00
|
|
|
@app.route("/_matrix/app/v1/transactions/<transaction>", methods=["PUT"])
|
2017-03-04 21:45:09 +00:00
|
|
|
@app.route("/transactions/<transaction>", methods=["PUT"])
|
2024-12-15 23:04:17 +00:00
|
|
|
async def on_receive_events(transaction):
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
access_token = request.args.get('access_token', '')
|
|
|
|
if access_token != app.config['MATRIX_HS_TOKEN']:
|
|
|
|
abort(403)
|
|
|
|
|
2017-03-04 21:45:09 +00:00
|
|
|
events = request.get_json()["events"]
|
|
|
|
for event in events:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug(event)
|
2018-01-10 00:28:53 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
if (app.config['MATRIX_ADMIN_ROOM'] and
|
|
|
|
app.config['MATRIX_ADMIN_ROOM'] == event['room_id']):
|
|
|
|
await on_admin_event(event)
|
|
|
|
return jsonify({})
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
user = Users.query.filter(Users.matrix_id ==
|
|
|
|
event['sender']).one_or_none()
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
if event['type'] == 'm.room.message':
|
2024-12-15 23:04:17 +00:00
|
|
|
await new_message(event, user)
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
# elif event['type'] == 'm.sticker':
|
|
|
|
# new_sticker(event, user)
|
2022-07-01 21:58:32 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
elif event['type'] == 'm.room.redaction':
|
|
|
|
delete_message(event, user)
|
2017-05-04 23:40:32 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
elif event['type'] == 'm.room.member':
|
2024-12-15 23:04:17 +00:00
|
|
|
if ('is_direct' in event['content'] and
|
|
|
|
'membership' in event['content']):
|
|
|
|
if (event['content']['membership'] == "invite" and
|
|
|
|
event['content']['is_direct']):
|
|
|
|
logging.debug('----> direct invite <----')
|
|
|
|
await on_direct_invite(event)
|
|
|
|
return jsonify({})
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2020-03-25 05:39:09 +00:00
|
|
|
if 'membership' in event['content']:
|
|
|
|
if event['content']['membership'] == "leave":
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug('----> leave event <----')
|
|
|
|
await on_leave_event(event)
|
|
|
|
return jsonify({})
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug("----room member event----")
|
|
|
|
logging.debug(user)
|
|
|
|
logging.debug(event)
|
2017-05-04 23:40:32 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
return jsonify({})
|
2018-05-09 00:58:43 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def new_message(event, user):
|
|
|
|
if (app.config['MATRIX_PNUT_PREFIX'] in event['sender'] or
|
|
|
|
'pnut-bridge' in event['sender']):
|
|
|
|
logging.debug('-skipping dup event-')
|
2019-01-04 03:49:38 +00:00
|
|
|
return
|
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
if 'msgtype' not in event['content']:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug('-unknown message type-')
|
2021-03-20 13:26:33 +00:00
|
|
|
return
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
control = ControlRooms.query.filter(ControlRooms.room_id ==
|
|
|
|
event['room_id']).one_or_none()
|
2021-03-20 13:26:33 +00:00
|
|
|
if control is not None:
|
2024-12-15 23:04:17 +00:00
|
|
|
await on_control_message(event)
|
|
|
|
return
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
direct = DirectRooms.query.filter(DirectRooms.room_id ==
|
|
|
|
event['room_id']).one_or_none()
|
2020-03-25 05:39:09 +00:00
|
|
|
if direct is not None:
|
2021-03-20 13:26:33 +00:00
|
|
|
return on_direct_message(event, user, direct)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
room = Rooms.query.filter(Rooms.room_id == event['room_id']).one_or_none()
|
|
|
|
if room is None:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug('-room not mapped-')
|
2019-01-04 03:49:38 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if user is not None:
|
|
|
|
token = user.pnut_user_token
|
|
|
|
prefix = ""
|
|
|
|
else:
|
|
|
|
token = app.config['MATRIX_PNUT_TOKEN']
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_profile = get_profile(event['sender'])
|
2020-05-10 04:55:45 +00:00
|
|
|
if "displayname" in matrix_profile:
|
2024-12-15 23:04:17 +00:00
|
|
|
prefix = (f"[{matrix_profile['displayname']}]"
|
|
|
|
f" ({event['sender']})\n")
|
2020-05-10 04:55:45 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
prefix = "(" + event['sender'] + ")\n"
|
2019-01-04 03:49:38 +00:00
|
|
|
pnutpy.api.add_authorization_token(token)
|
2017-05-04 06:01:51 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
raw = {}
|
|
|
|
raw['io.pnut.core.crosspost'] = [crosspost_raw(event)]
|
|
|
|
text, oembed = msg_from_event(event)
|
|
|
|
text = prefix + text
|
|
|
|
if oembed:
|
|
|
|
raw['io.pnut.core.oembed'] = [oembed]
|
|
|
|
logging.debug(oembed)
|
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
try:
|
2024-12-15 23:04:17 +00:00
|
|
|
msg, meta = pnutpy.api.create_message(room.pnut_chan,
|
|
|
|
data={'text': text, 'raw': raw})
|
2019-01-04 03:49:38 +00:00
|
|
|
revent = Events(
|
|
|
|
event_id=event['event_id'],
|
|
|
|
room_id=event['room_id'],
|
|
|
|
pnut_msg_id=msg.id,
|
|
|
|
pnut_user_id=msg.user.id,
|
|
|
|
pnut_chan_id=room.pnut_chan,
|
|
|
|
deleted=False
|
|
|
|
)
|
|
|
|
db_session.add(revent)
|
|
|
|
db_session.commit()
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
# TODO: need to redo this for global message
|
|
|
|
# if user is not None:
|
|
|
|
# cctag = re.search('##$', text)
|
|
|
|
# if cctag:
|
|
|
|
# raw = []
|
|
|
|
# cname = get_channel_settings(room.pnut_chan)['name']
|
|
|
|
# text = text[:-2]
|
|
|
|
# ftext = '\n\n[' + cname + "](https://patter.chat/room.html?channel=" + str(room.pnut_chan) + ")"
|
|
|
|
# mtext = textwrap.wrap(text + ftext, 254)
|
|
|
|
# if len(mtext) > 1:
|
|
|
|
# longpost = {
|
|
|
|
# 'title': "",
|
|
|
|
# 'body': text,
|
|
|
|
# 'tstamp': time.time() * 1000
|
|
|
|
# }
|
|
|
|
# pretext = textwrap.wrap(text, 100)
|
|
|
|
# text = pretext[0]
|
|
|
|
# text += "... - https://longpo.st/p/{object_id} - #longpost"
|
|
|
|
# raw.append({'type':"nl.chimpnut.blog.post", 'value': longpost})
|
|
|
|
#
|
|
|
|
# text += ftext
|
|
|
|
# r, meta = pnutpy.api.create_post(data={'text': text, 'raw': raw})
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception('-unable to post to pnut channel-')
|
2019-01-04 03:49:38 +00:00
|
|
|
return
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
except Exception:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception('-something bad happened here-')
|
2019-01-04 03:49:38 +00:00
|
|
|
return
|
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
def msg_from_event(event):
|
|
|
|
text = None
|
2024-12-15 23:04:17 +00:00
|
|
|
oembed = None
|
|
|
|
if (event['content']['msgtype'] == 'm.text' or
|
|
|
|
event['content']['msgtype'] == 'm.notice'):
|
2021-03-20 13:26:33 +00:00
|
|
|
text = event['content']['body']
|
|
|
|
|
|
|
|
elif event['content']['msgtype'] == 'm.emote':
|
|
|
|
text = "* " + event['content']['body']
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
elif (event['content']['msgtype'] == 'm.image' or
|
|
|
|
event['content']['msgtype'] == 'm.video' or
|
|
|
|
event['content']['msgtype'] == 'm.audio'):
|
|
|
|
oembed = oembed_from_event(event)
|
|
|
|
if ('title' in oembed and 'url' in oembed):
|
|
|
|
text = (f"[{oembed['title']}]"
|
|
|
|
f"({oembed['url']})")
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif event['content']['msgtype'] == 'm.file':
|
2024-12-15 23:04:17 +00:00
|
|
|
file_url = event['content']['url'][6:]
|
|
|
|
file_name = event['content']['body']
|
|
|
|
dl_url = (f"{app.config['MATRIX_URL']}"
|
|
|
|
f"/_matrix/client/v1/media/download/{file_url}"
|
|
|
|
f"/{file_name}")
|
|
|
|
text = (f"[{file_name}]"
|
|
|
|
f"({dl_url})")
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug('-unknown msg type- ' + event['content']['msgtype'])
|
2021-03-20 13:26:33 +00:00
|
|
|
return
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return text, oembed
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
def crosspost_raw(event):
|
2024-12-15 23:04:17 +00:00
|
|
|
cross_profile = {'username': event['sender']}
|
|
|
|
matrix_profile = get_profile(event['sender'])
|
2021-03-20 13:26:33 +00:00
|
|
|
if "avatar_url" in matrix_profile:
|
2024-12-15 23:04:17 +00:00
|
|
|
cross_profile['avatar_image'] = (f"{app.config['MATRIX_URL']}"
|
|
|
|
f"/_matrix/media/r0/download/"
|
|
|
|
f"{matrix_profile['avatar_url'][6:]}")
|
|
|
|
|
|
|
|
crosspost = {}
|
|
|
|
crosspost['canonical_url'] = (f"https://matrix.to/#/{event['room_id']}"
|
|
|
|
f"/{event['event_id']}"
|
|
|
|
f":{app.config['MATRIX_DOMAIN']}")
|
|
|
|
crosspost['source'] = {'name': "matrix.", 'url': "https://matrix.org"}
|
|
|
|
crosspost['user'] = cross_profile
|
|
|
|
|
|
|
|
return crosspost
|
|
|
|
|
|
|
|
# TODO: This could be used for uploading the media to pnut, maybe
|
|
|
|
# async def media_from_event(event):
|
|
|
|
# matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
# base_url=app.config['MATRIX_HOST'],
|
|
|
|
# token=app.config['MATRIX_AS_TOKEN'])
|
|
|
|
#
|
|
|
|
# mxc_url = event['content']['url']
|
|
|
|
# media_file = await matrix_api.download_media(mxc_url)
|
|
|
|
|
|
|
|
def oembed_from_event(event):
|
|
|
|
media_url = event['content']['url'][6:]
|
|
|
|
file_name = event['content']['body']
|
|
|
|
dl_url = (f"{app.config['MATRIX_URL']}"
|
|
|
|
f"/_matrix/client/v1/media/download/{media_url}"
|
|
|
|
f"/{file_name}")
|
|
|
|
|
|
|
|
oembed = {}
|
2019-01-04 03:49:38 +00:00
|
|
|
if event['content']['msgtype'] == 'm.image':
|
2024-12-15 23:04:17 +00:00
|
|
|
oembed['provider_name'] = "matrix"
|
|
|
|
oembed['provider_url'] = "https://matrix.org"
|
|
|
|
oembed['version'] = "1.0"
|
|
|
|
oembed['type'] = "photo"
|
|
|
|
oembed['title'] = file_name
|
|
|
|
oembed['url'] = dl_url
|
2019-01-04 03:49:38 +00:00
|
|
|
if 'info' in event['content']:
|
2019-02-02 23:14:24 +00:00
|
|
|
if 'h' in event['content']['info']:
|
2024-12-15 23:04:17 +00:00
|
|
|
oembed['height'] = event['content']['info']['h']
|
|
|
|
if 'w' in event['content']['info']:
|
|
|
|
oembed['width'] = event['content']['info']['w']
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
elif event['content']['msgtype'] == 'm.video':
|
2024-12-15 23:04:17 +00:00
|
|
|
oembed['provider_name'] = "matrix"
|
|
|
|
oembed['provider_url'] = "https://matrix.org"
|
|
|
|
oembed['version'] = "1.0"
|
|
|
|
oembed['type'] = "video"
|
|
|
|
oembed['title'] = file_name
|
|
|
|
oembed['url'] = dl_url
|
2019-01-04 03:49:38 +00:00
|
|
|
if 'info' in event['content']:
|
2024-12-15 23:04:17 +00:00
|
|
|
if 'h' in event['content']['info']:
|
|
|
|
oembed['height'] = event['content']['info']['h']
|
|
|
|
if 'w' in event['content']['info']:
|
|
|
|
oembed['width'] = event['content']['info']['w']
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
elif event['content']['msgtype'] == 'm.audio':
|
2024-12-15 23:04:17 +00:00
|
|
|
oembed['provider_name'] = "matrix"
|
|
|
|
oembed['provider_url'] = "https://matrix.org"
|
|
|
|
oembed['version'] = "1.0"
|
|
|
|
oembed['type'] = "audio"
|
|
|
|
oembed['title'] = file_name
|
|
|
|
oembed['url'] = dl_url
|
|
|
|
if 'info' in event['content']:
|
|
|
|
if 'duration' in event['content']['info']:
|
|
|
|
oembed['duration'] = event['content']['info']['duration']
|
2017-05-25 19:04:02 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return oembed
|
2017-05-25 19:04:02 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
def delete_message(event, user):
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
# TODO: should there be moderator handled redactions?
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
if user is not None:
|
|
|
|
token = user.pnut_user_token
|
|
|
|
else:
|
|
|
|
token = app.config['MATRIX_PNUT_TOKEN']
|
|
|
|
pnutpy.api.add_authorization_token(token)
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
e = Events.query.filter(and_(Events.event_id == event['redacts'],
|
|
|
|
Events.deleted == False)).one_or_none()
|
2019-01-04 03:49:38 +00:00
|
|
|
if e is None:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug("- can't find the event to remove -")
|
2019-01-04 03:49:38 +00:00
|
|
|
return
|
2023-02-16 02:08:51 +00:00
|
|
|
|
2019-02-02 23:20:30 +00:00
|
|
|
try:
|
|
|
|
r, meta = pnutpy.api.delete_message(e.pnut_chan_id, e.pnut_msg_id)
|
|
|
|
e.deleted = True
|
|
|
|
db_session.commit()
|
|
|
|
|
|
|
|
except pnutpy.errors.PnutPermissionDenied as e:
|
|
|
|
pass
|
2017-03-04 21:45:09 +00:00
|
|
|
|
2020-05-10 04:55:45 +00:00
|
|
|
def get_profile(userid):
|
2020-03-26 14:43:58 +00:00
|
|
|
url = app.config['MATRIX_HOST'] + "/_matrix/client/r0/profile/" + userid
|
2017-04-25 01:55:44 +00:00
|
|
|
r = requests.get(url)
|
|
|
|
if r.status_code == 200:
|
2020-05-10 04:55:45 +00:00
|
|
|
return json.loads(r.text)
|
2017-04-25 02:05:17 +00:00
|
|
|
return userid
|
2017-07-28 23:16:36 +00:00
|
|
|
|
|
|
|
def get_channel_settings(channel_id):
|
2019-01-04 03:49:38 +00:00
|
|
|
channel_settings = {}
|
|
|
|
try:
|
|
|
|
channel, meta = pnutpy.api.get_channel(channel_id, include_raw=1)
|
|
|
|
|
|
|
|
for item in channel.raw:
|
|
|
|
if item.type == 'io.pnut.core.chat-settings':
|
|
|
|
channel_settings = item.value
|
|
|
|
|
|
|
|
except Exception:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception('-unable to get channel settings-')
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
return channel_settings
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def create_pnut_matrix_room(channel, user):
|
|
|
|
name = None
|
|
|
|
topic = None
|
|
|
|
alias_localpart = f"{app.config['MATRIX_PNUT_PREFIX']}{channel.id}"
|
|
|
|
invitees = [user.matrix_id]
|
|
|
|
|
2022-06-30 19:47:31 +00:00
|
|
|
if channel.acl.read.public:
|
2024-12-15 23:04:17 +00:00
|
|
|
visibility = RoomDirectoryVisibility.PUBLIC
|
|
|
|
preset = RoomCreatePreset.PUBLIC
|
2022-06-30 19:47:31 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
visibility = RoomDirectoryVisibility.PRIVATE
|
|
|
|
preset = RoomCreatePreset.PRIVATE
|
|
|
|
|
|
|
|
if 'io.pnut.core.chat-settings' in channel.raw:
|
|
|
|
for setting in channel.raw['io.pnut.core.chat-settings']:
|
|
|
|
if 'name' in setting:
|
|
|
|
name = setting['name']
|
|
|
|
if 'description' in setting:
|
|
|
|
topic = setting['description']['text']
|
|
|
|
|
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
|
|
|
|
|
|
|
room_id = await matrix_api.create_room(alias_localpart,
|
|
|
|
invitees=invitees,
|
|
|
|
visibility=visibility,
|
|
|
|
preset=preset,
|
|
|
|
name=name,
|
|
|
|
topic=topic)
|
|
|
|
|
|
|
|
rr = Rooms(room_id=room_id, pnut_chan=channel.id, portal=True)
|
|
|
|
db_session.add(rr)
|
|
|
|
db_session.commit()
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
def new_matrix_user(username):
|
|
|
|
endpoint = "/_matrix/client/v3/register"
|
|
|
|
url = app.config['MATRIX_HOST'] + endpoint
|
|
|
|
params = {'kind': 'user'}
|
|
|
|
data = {
|
|
|
|
'type': 'm.login.application_service',
|
|
|
|
'username': app.config['MATRIX_PNUT_PREFIX'] + username
|
|
|
|
}
|
2023-07-04 16:33:24 +00:00
|
|
|
headers = {
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
"Authorization": "Bearer " + app.config['MATRIX_AS_TOKEN']
|
|
|
|
}
|
2024-12-15 23:04:17 +00:00
|
|
|
r = requests.post(url, headers=headers, json=data, params=params)
|
2021-03-20 13:26:33 +00:00
|
|
|
if r.status_code == 200:
|
2024-12-15 23:04:17 +00:00
|
|
|
return
|
2023-07-04 16:33:24 +00:00
|
|
|
|
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
errmsg = f"- unable to register {username} -"
|
|
|
|
logging.warning(errmsg)
|
|
|
|
logging.debug(r.status_code)
|
|
|
|
logging.debug(r.text)
|
|
|
|
return
|
2022-06-12 04:55:06 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def on_admin_event(event):
|
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
2022-06-12 04:55:06 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug("- admin room event recieved -")
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
if event['type'] != 'm.room.message':
|
|
|
|
return jsonify({})
|
2023-02-16 02:08:51 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
msg = event['content']['body'].split(' ')
|
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
try:
|
|
|
|
if msg[0] == 'help':
|
|
|
|
if len(msg) > 1:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_admin_help(msg[1]))
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_admin_help())
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == 'list':
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'], cmd_admin_list())
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == 'unlink':
|
|
|
|
if len(msg) > 1:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_admin_unlink(msg[1]))
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_admin_help('unlink'))
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == 'link':
|
|
|
|
if len(msg) > 2:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_admin_link(msg[1], msg[2]))
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_admin_help('link'))
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
except Exception:
|
|
|
|
errmsg = "- on_admin_event -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
def cmd_admin_help(cmd=None):
|
|
|
|
help_usage = "help [command]"
|
|
|
|
help_desc = "Show information about available commands."
|
|
|
|
list_usage = "list"
|
|
|
|
list_desc = "List the rooms currently linked with pnut.io."
|
|
|
|
unlink_usage = "unlink <room_id> | <pnut_channel_id>"
|
|
|
|
unlink_desc = "Unlink a room between Matrix and pnut.io."
|
|
|
|
link_usage = "link <room_id> <pnut_channel_id>"
|
|
|
|
link_desc = "Link a room between Matrix and pnut.io."
|
|
|
|
|
|
|
|
if cmd == 'help':
|
|
|
|
text = "usage: " + help_usage + "\n\n"
|
|
|
|
text += help_desc
|
|
|
|
if cmd == 'list':
|
|
|
|
text = "usage: " + list_usage + "\n\n"
|
|
|
|
text += list_desc
|
|
|
|
elif cmd == 'unlink':
|
|
|
|
text = "usage: " + unlink_usage + "\n\n"
|
|
|
|
text += unlink_desc
|
|
|
|
elif cmd == 'link':
|
|
|
|
text = "usage: " + link_usage + "\n\n"
|
|
|
|
text += link_desc
|
|
|
|
else:
|
|
|
|
text = "The following commands are available:\n\n"
|
|
|
|
text += help_usage + "\n"
|
|
|
|
text += list_usage + "\n"
|
|
|
|
text += unlink_usage + "\n"
|
|
|
|
text += link_usage + "\n"
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=text)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
def cmd_admin_list():
|
|
|
|
text = ""
|
|
|
|
rooms = Rooms.query.all()
|
|
|
|
|
|
|
|
if len(rooms) > 0:
|
|
|
|
text = "ID\tMATRIX ID\tPNUT CHANNEL\n"
|
|
|
|
else:
|
|
|
|
text = " - no rooms are currently linked - \n"
|
|
|
|
|
|
|
|
for room in rooms:
|
|
|
|
text += str(room.id) + '\t'
|
|
|
|
text += room.room_id + '\t\t\t\t\t'
|
|
|
|
text += str(room.pnut_chan) + '\t'
|
|
|
|
if room.portal:
|
|
|
|
text += "(portal)"
|
|
|
|
text += '\n'
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=text)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def cmd_admin_link(room_id, pnut_chan_id):
|
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
2019-01-04 03:49:38 +00:00
|
|
|
pnutpy.api.add_authorization_token(app.config['MATRIX_PNUT_TOKEN'])
|
|
|
|
|
|
|
|
mrcheck = Rooms.query.filter(Rooms.room_id == room_id).one_or_none()
|
|
|
|
pncheck = Rooms.query.filter(Rooms.pnut_chan == pnut_chan_id).one_or_none()
|
|
|
|
|
|
|
|
if mrcheck is not None or pncheck is not None:
|
2024-12-15 23:04:17 +00:00
|
|
|
text = "- room may already be linked -"
|
|
|
|
return TextMessageEventContent(msgtype='m.text', body=text)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
channel, meta = pnutpy.api.subscribe_channel(pnut_chan_id)
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.join_room(room_id)
|
2023-02-16 02:08:51 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
rec = Rooms(
|
|
|
|
room_id=room_id,
|
|
|
|
pnut_chan=channel.id,
|
|
|
|
portal=False
|
|
|
|
)
|
|
|
|
db_session.add(rec)
|
|
|
|
db_session.commit()
|
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException:
|
|
|
|
errmsg = "- unable to subscribe to channel -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
|
|
|
return TextMessageEventContent(msgtype='m.text', body=errmsg)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
except Exception:
|
|
|
|
errmsg = "- unable to link room for some reason -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
|
|
|
return TextMessageEventContent(msgtype='m.text', body=errmsg)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def cmd_admin_unlink(rid):
|
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
2019-01-04 03:49:38 +00:00
|
|
|
pnutpy.api.add_authorization_token(app.config['MATRIX_PNUT_TOKEN'])
|
|
|
|
|
2022-06-30 19:47:31 +00:00
|
|
|
if rid.startswith('!'):
|
|
|
|
room = Rooms.query.filter(Rooms.room_id == rid).one_or_none()
|
2019-01-04 03:49:38 +00:00
|
|
|
else:
|
2022-06-30 19:47:31 +00:00
|
|
|
room = Rooms.query.filter(Rooms.pnut_chan == rid).one_or_none()
|
2019-01-04 03:49:38 +00:00
|
|
|
|
2020-03-23 05:00:53 +00:00
|
|
|
if hasattr(room, 'portal'):
|
|
|
|
if room.portal:
|
|
|
|
alias = "#" + app.config['MATRIX_PNUT_PREFIX']
|
|
|
|
alias += str(room.pnut_chan) + ":"
|
|
|
|
alias += app.config['MATRIX_DOMAIN']
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.remove_room_alias(alias)
|
2020-03-23 05:00:53 +00:00
|
|
|
|
|
|
|
# Kicking users needs at least moderator privs
|
2024-12-15 23:04:17 +00:00
|
|
|
members = await matrix_api.get_members(room.room_id)
|
2020-03-23 05:00:53 +00:00
|
|
|
reason = "Portal room has been unlinked by administrator"
|
|
|
|
for m in members['chunk']:
|
2024-12-15 23:04:17 +00:00
|
|
|
if (m['content']['membership'] == 'join' and
|
|
|
|
m['sender'] != app.config['MATRIX_AS_ID']):
|
2020-03-23 05:00:53 +00:00
|
|
|
if room.portal:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.kick_user(room.room_id,
|
|
|
|
m['sender'],
|
|
|
|
reason=reason)
|
2020-03-23 05:00:53 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
prefix = f"@{app.config['MATRIX_PNUT_PREFIX']}"
|
|
|
|
if m['sender'].startswith(prefix):
|
|
|
|
await matrix_api.kick_user(room.room_id,
|
|
|
|
m['sender'],
|
|
|
|
reason=reason)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
channel, meta = pnutpy.api.unsubscribe_channel(room.pnut_chan)
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.leave_room(room.room_id)
|
2019-01-04 03:49:38 +00:00
|
|
|
|
|
|
|
if room is not None:
|
|
|
|
db_session.delete(room)
|
|
|
|
db_session.commit()
|
2024-12-15 23:04:17 +00:00
|
|
|
text = "- room has been unlinked -"
|
2019-01-04 03:49:38 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
text = "- unable to locate room to unlink -"
|
|
|
|
|
|
|
|
return TextMessageEventContent(msgtype='m.text', body=text)
|
2017-07-28 23:16:36 +00:00
|
|
|
|
2019-01-04 03:49:38 +00:00
|
|
|
except Exception:
|
|
|
|
errmsg = "- error while unlinking room -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
|
|
|
return TextMessageEventContent(msgtype='m.text', body=errmsg)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def on_direct_invite(event):
|
2021-03-20 13:26:33 +00:00
|
|
|
if event['state_key'] == app.config['MATRIX_AS_ID']:
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
2021-03-20 13:26:33 +00:00
|
|
|
dm = ControlRooms(room_id=event['room_id'])
|
|
|
|
|
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'],
|
|
|
|
as_user_id=event['state_key'])
|
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
bridge_user = event['state_key']
|
2024-12-15 23:04:17 +00:00
|
|
|
pnut_user = bridge_user.replace(app.config['MATRIX_PNUT_PREFIX'],
|
|
|
|
'').split(':')[0]
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
user = Users.query.filter(Users.matrix_id ==
|
|
|
|
event['sender']).one_or_none()
|
2021-03-20 13:26:33 +00:00
|
|
|
if user is not None:
|
|
|
|
# TODO: need to handle if the user isn't registered
|
|
|
|
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
|
|
|
channel, meta = pnutpy.api.existing_pm(ids=pnut_user)
|
2022-06-12 04:55:06 +00:00
|
|
|
new_matrix_user(pnut_user)
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
dm = DirectRooms(room_id=event['room_id'],
|
|
|
|
bridge_user=bridge_user, pnut_chan=channel.id)
|
|
|
|
|
|
|
|
try:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.debug('--> trying to join room <--')
|
|
|
|
await matrix_api.join_room_by_id(event['room_id'])
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
db_session.add(dm)
|
|
|
|
db_session.commit()
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
errmsg = "- on_direct_invite -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def on_leave_event(event):
|
|
|
|
direct = DirectRooms.query.filter(DirectRooms.room_id ==
|
|
|
|
event['room_id']).one_or_none()
|
2020-03-25 05:39:09 +00:00
|
|
|
if direct is not None:
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'],
|
|
|
|
as_user_id=direct.bridge_user.lower())
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
try:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.leave_room(event['room_id'])
|
2021-03-20 13:26:33 +00:00
|
|
|
db_session.delete(direct)
|
|
|
|
db_session.commit()
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
errmsg = "- on_leave_event -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
control = ControlRooms.query.filter(ControlRooms.room_id ==
|
|
|
|
event['room_id']).one_or_none()
|
2021-03-20 13:26:33 +00:00
|
|
|
if control is not None:
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
2021-03-20 13:26:33 +00:00
|
|
|
try:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.leave_room(event['room_id'])
|
2021-03-20 13:26:33 +00:00
|
|
|
db_session.delete(control)
|
|
|
|
db_session.commit()
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
errmsg = "- on_leave_event -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
def on_direct_message(event, user, room):
|
|
|
|
if user is not None:
|
|
|
|
token = user.pnut_user_token
|
|
|
|
prefix = ""
|
|
|
|
else:
|
|
|
|
token = app.config['MATRIX_PNUT_TOKEN']
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_profile = get_profile(event['sender'])
|
2021-03-20 13:26:33 +00:00
|
|
|
if "displayname" in matrix_profile:
|
2024-12-15 23:04:17 +00:00
|
|
|
prefix = (f"[{matrix_profile['displayname']}]"
|
|
|
|
f" ({event['sender']})\n")
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
prefix = "(" + event['sender'] + ")\n"
|
2021-03-20 13:26:33 +00:00
|
|
|
pnutpy.api.add_authorization_token(token)
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
raw = {}
|
|
|
|
raw['io.pnut.core.crosspost'] = [crosspost_raw(event)]
|
2021-03-20 13:26:33 +00:00
|
|
|
evtext, evraw = msg_from_event(event)
|
|
|
|
text = prefix + evtext
|
|
|
|
try:
|
2024-12-15 23:04:17 +00:00
|
|
|
msg, meta = pnutpy.api.create_message(room.pnut_chan,
|
|
|
|
data={'text': text, 'raw': raw})
|
2021-03-20 13:26:33 +00:00
|
|
|
revent = Events(
|
|
|
|
event_id=event['event_id'],
|
|
|
|
room_id=event['room_id'],
|
|
|
|
pnut_msg_id=msg.id,
|
|
|
|
pnut_user_id=msg.user.id,
|
|
|
|
pnut_chan_id=room.pnut_chan,
|
|
|
|
deleted=False
|
|
|
|
)
|
|
|
|
db_session.add(revent)
|
2020-03-25 05:39:09 +00:00
|
|
|
db_session.commit()
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception('-unable to post to pnut channel-')
|
2023-02-16 02:08:51 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
except Exception:
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception('-something bad happened here-')
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2020-03-25 05:39:09 +00:00
|
|
|
return jsonify({})
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def on_control_message(event):
|
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
|
|
|
logging.debug("- direct room event received -")
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
if event['type'] != 'm.room.message':
|
|
|
|
return jsonify({})
|
2023-02-16 02:08:51 +00:00
|
|
|
|
2020-03-25 05:39:09 +00:00
|
|
|
msg = event['content']['body'].split(' ')
|
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
try:
|
|
|
|
if msg[0] == '!help' or msg[0] == 'help':
|
|
|
|
if len(msg) > 1:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_user_help(msg[1]))
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_user_help())
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == '!auth':
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'], cmd_user_auth())
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == '!save':
|
|
|
|
if len(msg) > 1:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_user_save(event['sender'],
|
|
|
|
msg[1]))
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_user_save())
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == '!drop':
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_user_drop(event['sender']))
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2021-03-20 13:26:33 +00:00
|
|
|
elif msg[0] == '!status':
|
2024-12-15 23:04:17 +00:00
|
|
|
await matrix_api.send_message(event['room_id'],
|
|
|
|
cmd_user_status(event['sender']))
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
elif msg[0] == '!join':
|
|
|
|
if len(msg) > 1:
|
2024-12-15 23:04:17 +00:00
|
|
|
r = await cmd_user_join(event['sender'], msg[1])
|
|
|
|
await matrix_api.send_message(event['room_id'], r)
|
2021-03-20 13:26:33 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
r = await cmd_user_join(event['sender'])
|
|
|
|
await matrix_api.send_message(event['room_id'], r)
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
except Exception:
|
|
|
|
errmsg = "- on_direct_message -"
|
2024-12-15 23:04:17 +00:00
|
|
|
logging.exception(errmsg)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
def cmd_user_help(cmd=None):
|
|
|
|
reply = "This is an admin room for controlling your connection to pnut.io\n"
|
|
|
|
reply += "The following commands are available.\n\n"
|
|
|
|
reply += "!auth\t\t\t- Authorize your account on pnut.io\n"
|
|
|
|
reply += "!save <token>\t- Save your pnut.io auth token\n"
|
|
|
|
reply += "!drop\t\t\t- Drop your pnut.io auth token\n"
|
|
|
|
reply += "!status\t\t\t- Status of your pnut.io auth token\n"
|
2021-03-20 13:26:33 +00:00
|
|
|
reply += "!join <channel #>\t- Join a private channel on pnut.io\n"
|
2020-03-25 05:39:09 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
def cmd_user_auth():
|
|
|
|
reply = "Visit the following URL to authorize your account on pnut.io.\n\n"
|
|
|
|
reply += "https://pnut.io/oauth/authenticate"
|
|
|
|
reply += "?client_id=6SeCRCpCZkmZOKFLFGWbcdAeq2fX1M5t"
|
|
|
|
reply += "&redirect_uri=urn:ietf:wg:oauth:2.0:oob"
|
|
|
|
reply += "&scope=write_post,presence,messages&response_type=token\n\n"
|
|
|
|
reply += "You will be provided with a token that you store with the !save command.\n"
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
def cmd_user_save(sender=None, token=None):
|
|
|
|
if token is None:
|
|
|
|
reply = "You must provide a token with this command.\n"
|
|
|
|
reply += "!save <token>"
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
pnutpy.api.add_authorization_token(token)
|
|
|
|
try:
|
|
|
|
response, meta = pnutpy.api.get_user('me')
|
|
|
|
|
|
|
|
user = Users(
|
|
|
|
matrix_id=sender,
|
|
|
|
pnut_user_id=response.id,
|
|
|
|
pnut_user_token=token
|
|
|
|
)
|
|
|
|
db_session.add(user)
|
|
|
|
db_session.commit()
|
|
|
|
|
|
|
|
reply = "Success! You are now authorized as " + response['username']
|
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException as e:
|
|
|
|
reply = "Error! Unable to authorize your account."
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception('!save')
|
|
|
|
reply = "Error! Problem saving your token."
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
def cmd_user_drop(sender=None):
|
|
|
|
try:
|
|
|
|
user = Users.query.filter(Users.matrix_id == sender).one_or_none()
|
|
|
|
if user is not None:
|
|
|
|
db_session.delete(user)
|
|
|
|
db_session.commit()
|
|
|
|
reply = "Success! Your auth token has been removed."
|
|
|
|
else:
|
2023-02-16 02:08:51 +00:00
|
|
|
reply = "You do not appear to be registered."
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception('!drop')
|
|
|
|
reply = "Error! Problem removing your token."
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2020-03-25 05:39:09 +00:00
|
|
|
|
|
|
|
def cmd_user_status(sender=None):
|
|
|
|
try:
|
|
|
|
user = Users.query.filter(Users.matrix_id == sender).one_or_none()
|
|
|
|
if user is None:
|
|
|
|
reply = "You are currently not authorized on pnut.io"
|
|
|
|
else:
|
|
|
|
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
|
|
|
response, meta = pnutpy.api.get_user('me')
|
|
|
|
reply = "You are currently authorized as " + response.username
|
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException as e:
|
|
|
|
reply = "You are currently not authorized on pnut.io"
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception('!status')
|
|
|
|
reply = "Error! There was a problem checking your account."
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2021-03-20 13:26:33 +00:00
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
async def cmd_user_join(sender=None, channel_id=None):
|
2021-03-20 13:26:33 +00:00
|
|
|
if channel_id is None:
|
|
|
|
reply = "You must provide a channel id number with this command.\n"
|
|
|
|
reply += "!join <channel #>"
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
user = Users.query.filter(Users.matrix_id == sender).one_or_none()
|
|
|
|
if user is None:
|
|
|
|
reply = "You are currently not authorized on pnut.io"
|
|
|
|
else:
|
|
|
|
pnutpy.api.add_authorization_token(user.pnut_user_token)
|
|
|
|
channel, meta = pnutpy.api.get_channel(channel_id, include_raw=1)
|
2024-12-15 23:04:17 +00:00
|
|
|
room = Rooms.query.filter(Rooms.pnut_chan ==
|
|
|
|
channel_id).one_or_none()
|
2022-06-30 19:47:31 +00:00
|
|
|
if room is None:
|
2024-12-15 23:04:17 +00:00
|
|
|
await create_pnut_matrix_room(channel, user)
|
2022-06-30 19:47:31 +00:00
|
|
|
else:
|
2024-12-15 23:04:17 +00:00
|
|
|
matrix_api = ClientAPI(app.config['MATRIX_AS_ID'],
|
|
|
|
base_url=app.config['MATRIX_HOST'],
|
|
|
|
token=app.config['MATRIX_AS_TOKEN'])
|
|
|
|
await matrix_api.invite_user(room.room_id, sender)
|
2022-06-30 19:47:31 +00:00
|
|
|
reply = "ok"
|
2021-03-20 13:26:33 +00:00
|
|
|
|
|
|
|
except pnutpy.errors.PnutAuthAPIException as e:
|
|
|
|
reply = "You are currently not authorized on pnut.io"
|
|
|
|
|
|
|
|
except pnutpy.errors.PnutPermissionDenied:
|
|
|
|
reply = "You are not authorized for this channel"
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
logging.exception('!join')
|
|
|
|
reply = "Error! There was a problem joining the channel."
|
|
|
|
|
2024-12-15 23:04:17 +00:00
|
|
|
return TextMessageEventContent(msgtype='m.text', body=reply)
|
|
|
|
|
|
|
|
class MLogFilter(logging.Filter):
|
|
|
|
|
|
|
|
ACCESS_TOKEN_RE = re.compile(r"(\?.*access(_|%5[Ff])token=)[^&]*(\s.*)$")
|
|
|
|
ACCESS_TOKEN_RE2 = re.compile(r"(\?.*access(_|%5[Ff])token=)[^&]*(.*)$")
|
|
|
|
|
|
|
|
def filter(self, record):
|
|
|
|
if record.name == "werkzeug" and len(record.args) > 0:
|
|
|
|
redacted_uri = MLogFilter.ACCESS_TOKEN_RE.sub(r"\1<redacted>\3",
|
|
|
|
record.args[0])
|
|
|
|
record.args = (redacted_uri, ) + record.args[1:]
|
|
|
|
elif record.name == "urllib3.connectionpool" and len(record.args) > 3:
|
|
|
|
redacted_uri = MLogFilter.ACCESS_TOKEN_RE2.sub(r"\1<redacted>\3",
|
|
|
|
record.args[4])
|
|
|
|
record.args = record.args[:4] + (redacted_uri,) + record.args[5:]
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
configyaml = os.environ.get("CONFIG_FILE")
|
|
|
|
|
|
|
|
with open(configyaml, "rb") as config_file:
|
|
|
|
config = yaml.load(config_file, Loader=yaml.SafeLoader)
|
|
|
|
|
|
|
|
logging.config.dictConfig(config['logging'])
|
|
|
|
redact_filter = MLogFilter()
|
|
|
|
logging.getLogger("werkzeug").addFilter(redact_filter)
|
|
|
|
logging.getLogger("urllib3.connectionpool").addFilter(redact_filter)
|
|
|
|
|
|
|
|
app.config.update(config)
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
app.run(host=config['LISTEN_HOST'], port=config['LISTEN_PORT'])
|