Compare commits

...

10 Commits

Author SHA1 Message Date
Tulir Asokan 489d09a0f6 Bump version to 0.6.1rc2 2019-09-03 00:34:51 +03:00
Tulir Asokan d96356a310 Remove invalid reply fallbacks from edits 2019-09-03 00:33:58 +03:00
Tulir Asokan d3c3912645 Add .gitlab-ci.yml 2019-09-03 00:32:45 +03:00
Tulir Asokan 92830c3a64 Bump version to 0.6.0rc1 2019-09-03 00:23:35 +03:00
Tulir Asokan 00faab2213 Ignore Riot web brokenness in edits 2019-09-03 00:22:45 +03:00
Tulir Asokan d6294ebb45 Fix some errors 2019-09-03 00:17:52 +03:00
Tulir Asokan 87aa0b6659 Limit displaynames sent to Matrix to 100 characters 2019-07-18 23:23:15 +03:00
Tulir Asokan bb167b14ef Add/remove reply fallbacks in m.new_content 2019-07-18 23:22:57 +03:00
Tulir Asokan 9a8f8433b0 Bump version to 0.6.0 2019-07-09 19:43:56 +03:00
Tulir Asokan 4942789213 Fix vulnerability in event handling 2019-07-09 19:43:37 +03:00
7 changed files with 120 additions and 59 deletions
+38
View File
@@ -0,0 +1,38 @@
image: docker:stable
stages:
- build
- push
default:
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
build:
stage: build
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --pull --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
push latest:
stage: push
only:
- master
variables:
GIT_STRATEGY: none
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
push tag:
stage: push
variables:
GIT_STRATEGY: none
except:
- master
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
+1 -1
View File
@@ -1,2 +1,2 @@
__version__ = "0.6.0rc2"
__version__ = "0.6.1rc2"
__author__ = "Tulir Asokan <tulir@maunium.net>"
@@ -170,7 +170,9 @@ class MatrixParser:
@classmethod
def node_to_tmessage(cls, node: HTMLNode, ctx: RecursionContext) -> TelegramMessage:
if node.tag == "ol":
if node.tag == "mx-reply":
return TelegramMessage("")
elif node.tag == "ol":
return cls.list_to_tmessage(node, ctx)
elif node.tag == "ul":
return cls.list_to_tmessage(node, ctx.enter_list())
+59 -48
View File
@@ -399,12 +399,24 @@ class MatrixHandler:
return (sender == self.az.bot_mxid
or pu.Puppet.get_id_from_mxid(sender) is not None)
async def try_handle_event(self, evt: MatrixEvent) -> None:
async def try_handle_ephemeral_event(self, evt: MatrixEvent) -> None:
try:
await self.handle_event(evt)
await self.handle_ephemeral_event(evt)
except Exception:
self.log.exception("Error handling manually received Matrix event")
async def handle_ephemeral_event(self, evt: MatrixEvent) -> None:
evt_type = evt.get("type", "m.unknown") # type: str
room_id = evt.get("room_id", None) # type: Optional[MatrixRoomID]
sender = evt.get("sender", None) # type: Optional[MatrixUserID]
content = evt.get("content", {}) # type: Dict
if evt_type == "m.receipt":
await self.handle_read_receipts(room_id, self.parse_read_receipts(content))
elif evt_type == "m.presence":
await self.handle_presence(sender, content.get("presence", "offline"))
elif evt_type == "m.typing":
await self.handle_typing(room_id, content.get("user_ids", []))
async def handle_event(self, evt: MatrixEvent) -> None:
if self.filter_matrix_event(evt):
return
@@ -414,53 +426,52 @@ class MatrixHandler:
room_id = evt.get("room_id", None) # type: Optional[MatrixRoomID]
event_id = evt.get("event_id", None) # type: Optional[MatrixEventID]
sender = evt.get("sender", None) # type: Optional[MatrixUserID]
state_key = evt.get("state_key", None)
content = evt.get("content", {}) # type: Dict
if evt_type == "m.room.member":
state_key = evt["state_key"] # type: MatrixUserID
prev_content = evt.get("unsigned", {}).get("prev_content", {}) # type: Dict
membership = content.get("membership", "") # type: str
prev_membership = prev_content.get("membership", "leave") # type: str
if membership == prev_membership:
match = re.compile("@(.+):(.+)").match(state_key) # type: Match
mxid = match.group(0) # type: str
displayname = content.get("displayname", None) or mxid # type: str
prev_displayname = prev_content.get("displayname", None) or mxid # type: str
if displayname != prev_displayname:
await self.handle_name_change(room_id, state_key, displayname,
prev_displayname, event_id)
elif membership == "invite":
await self.handle_invite(room_id, state_key, sender)
elif prev_membership == "join" and membership == "leave":
await self.handle_part(room_id, state_key, sender, event_id)
elif membership == "join":
await self.handle_join(room_id, state_key, event_id)
elif evt_type in ("m.room.message", "m.sticker"):
if evt_type != "m.room.message":
content["msgtype"] = evt_type
await self.handle_message(room_id, sender, content, event_id)
elif evt_type == "m.room.redaction":
await self.handle_redaction(room_id, sender, evt["redacts"])
elif evt_type == "m.room.power_levels":
prev_content = evt.get("unsigned", {}).get("prev_content", {})
await self.handle_power_levels(room_id, sender, evt["content"], prev_content)
elif evt_type in ("m.room.name", "m.room.avatar", "m.room.topic"):
await self.handle_room_meta(evt_type, room_id, sender, evt["content"])
elif evt_type == "m.room.pinned_events":
new_events = set(evt["content"]["pinned"])
try:
old_events = set(evt["unsigned"]["prev_content"]["pinned"])
except KeyError:
old_events = set()
await self.handle_room_pin(room_id, sender, new_events, old_events)
elif evt_type == "m.room.tombstone":
await self.handle_room_upgrade(room_id, evt["content"]["replacement_room"])
elif evt_type == "m.receipt":
await self.handle_read_receipts(room_id, self.parse_read_receipts(content))
elif evt_type == "m.presence":
await self.handle_presence(sender, content.get("presence", "offline"))
elif evt_type == "m.typing":
await self.handle_typing(room_id, content.get("user_ids", []))
if state_key is not None:
if evt_type == "m.room.member":
prev_content = evt.get("unsigned", {}).get("prev_content", {}) # type: Dict
membership = content.get("membership", "") # type: str
prev_membership = prev_content.get("membership", "leave") # type: str
if membership == prev_membership:
match = re.compile("@(.+):(.+)").match(state_key) # type: Match
mxid = match.group(0) # type: str
displayname = content.get("displayname", None) or mxid # type: str
prev_displayname = prev_content.get("displayname", None) or mxid # type: str
if displayname != prev_displayname:
await self.handle_name_change(room_id, state_key, displayname,
prev_displayname, event_id)
elif membership == "invite":
await self.handle_invite(room_id, state_key, sender)
elif prev_membership == "join" and membership == "leave":
await self.handle_part(room_id, state_key, sender, event_id)
elif membership == "join":
await self.handle_join(room_id, state_key, event_id)
elif evt_type == "m.room.power_levels":
prev_content = evt.get("unsigned", {}).get("prev_content", {})
await self.handle_power_levels(room_id, sender, evt["content"], prev_content)
elif evt_type in ("m.room.name", "m.room.avatar", "m.room.topic"):
await self.handle_room_meta(evt_type, room_id, sender, evt["content"])
elif evt_type == "m.room.pinned_events":
new_events = set(evt["content"]["pinned"])
try:
old_events = set(evt["unsigned"]["prev_content"]["pinned"])
except KeyError:
old_events = set()
await self.handle_room_pin(room_id, sender, new_events, old_events)
elif evt_type == "m.room.tombstone":
await self.handle_room_upgrade(room_id, evt["content"]["replacement_room"])
else:
return
else:
return
if evt_type in ("m.room.message", "m.sticker"):
if evt_type != "m.room.message":
content["msgtype"] = evt_type
await self.handle_message(room_id, sender, content, event_id)
elif evt_type == "m.room.redaction":
await self.handle_redaction(room_id, sender, evt["redacts"])
else:
return
if EVENT_TIME:
EVENT_TIME.labels(event_type=evt_type).observe(time.time() - start_time)
+8 -4
View File
@@ -346,7 +346,10 @@ class Portal:
await self.invite_to_matrix(invites or [])
return self.mxid
async with self._room_create_lock:
return await self._create_matrix_room(user, entity, invites)
try:
return await self._create_matrix_room(user, entity, invites)
except Exception:
self.log.exception("Fatal error creating Matrix room")
async def _create_matrix_room(self, user: 'AbstractUser', entity: TypeChat, invites: InviteList
) -> Optional[MatrixRoomID]:
@@ -996,9 +999,10 @@ class Portal:
relates_to = message.get("m.relates_to", None) or {}
if relates_to.get("rel_type", None) == "m.replace":
orig_msg = DBMessage.get_by_mxid(relates_to.get("event_id", ""), self.mxid, space)
if orig_msg:
response = await client.edit_message(self.peer, orig_msg.tgid,
message.get("m.new_content", message),
if orig_msg and "m.new_content" in message:
message = message["m.new_content"]
formatter.matrix_reply_to_telegram(message, space, room_id=self.mxid)
response = await client.edit_message(self.peer, orig_msg.tgid, message,
parse_mode=self._matrix_event_to_entities,
link_preview=lp)
self._add_telegram_message_to_db(event_id, space, -1, response)
+3 -3
View File
@@ -221,13 +221,13 @@ class Puppet:
return new_events
def handle_sync(self, presence: List, ephemeral: Dict) -> None:
presence_events = [self.mx.try_handle_event(event) for event in presence]
presence_events = [self.mx.try_handle_ephemeral_event(event) for event in presence]
for room_id, events in ephemeral.items():
for event in events:
event["room_id"] = room_id
ephemeral_events = [self.mx.try_handle_event(event)
ephemeral_events = [self.mx.try_handle_ephemeral_event(event)
for events in ephemeral.values()
for event in self.filter_events(events)]
@@ -379,7 +379,7 @@ class Puppet:
self.displayname = displayname
self.displayname_source = source.tgid
try:
await self.default_mxid_intent.set_display_name(displayname)
await self.default_mxid_intent.set_display_name(displayname[:100])
except MatrixRequestError:
self.log.exception("Failed to set displayname")
self.displayname = ""
+8 -2
View File
@@ -161,6 +161,12 @@ class User(AbstractUser):
# endregion
# region Telegram connection management
async def try_ensure_started(self) -> None:
try:
await self.ensure_started()
except Exception:
self.log.exception("Exception in ensure_started")
def ensure_started(self, even_if_no_session=False) -> Awaitable['User']:
return super().ensure_started(even_if_no_session)
@@ -400,9 +406,9 @@ class User(AbstractUser):
# endregion
def init(context: 'Context') -> List[Awaitable['User']]:
def init(context: 'Context') -> List[Awaitable[None]]:
global config
config = context.config
users = [User.from_db(user) for user in DBUser.all()]
return [user.ensure_started() for user in users if user.tgid]
return [user.try_ensure_started() for user in users if user.tgid]