Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix power level assignment for non-double-puppeted users, some cleanup #333

Merged
merged 1 commit into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions mausignald/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,19 +160,6 @@ class Profile(SerializableAttrs):
# visible_badge_ids: List[str]


@dataclass
class Group(SerializableAttrs):
group_id: GroupID = field(json="groupId")
name: str = "Unknown group"

# Sometimes "UPDATE"
type: Optional[str] = None

# Not always present
members: List[Address] = field(factory=lambda: [])
avatar_id: int = field(default=0, json="avatarId")


class AccessControlMode(SerializableEnum):
UNKNOWN = "UNKNOWN"
ANY = "ANY"
Expand Down Expand Up @@ -426,7 +413,6 @@ class MessageData(SerializableAttrs):
mentions: List[Mention] = field(factory=lambda: [])
contacts: List[SharedContact] = field(factory=lambda: [])

group: Optional[Group] = None
group_v2: Optional[GroupV2ID] = field(default=None, json="groupV2")

end_session: bool = field(default=False, json="endSession")
Expand Down
125 changes: 52 additions & 73 deletions mautrix_signal/portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
Address,
AnnouncementsMode,
Attachment,
Group,
GroupAccessControl,
GroupChange,
GroupID,
Expand Down Expand Up @@ -119,7 +118,7 @@

StateBridge = EventType.find("m.bridge", EventType.Class.STATE)
StateHalfShotBridge = EventType.find("uk.half-shot.bridge", EventType.Class.STATE)
ChatInfo = Union[Group, GroupV2, GroupV2ID, Profile, Address]
ChatInfo = Union[GroupV2, Profile, Address]
MAX_MATRIX_MESSAGE_SIZE = 30000
BEEPER_LINK_PREVIEWS_KEY = "com.beeper.linkpreviews"
BEEPER_IMAGE_ENCRYPTION_KEY = "beeper:image:encryption"
Expand Down Expand Up @@ -1868,7 +1867,7 @@ async def bridge_signal_group(
# endregion
# region Updating portal info

async def update_info(self, source: u.User, info: ChatInfo) -> None:
async def update_info(self, source: u.User, info: ChatInfo | GroupV2ID) -> None:
if self.is_direct:
if not isinstance(info, (Profile, Address)):
raise ValueError(f"Unexpected type for direct chat update_info: {type(info)}")
Expand Down Expand Up @@ -1898,24 +1897,17 @@ async def update_info(self, source: u.User, info: ChatInfo) -> None:
return

changed = False
if isinstance(info, Group):
changed = await self._update_name(info.name) or changed
elif isinstance(info, GroupV2):
if self.revision < info.revision:
self.revision = info.revision
changed = True
elif self.revision > info.revision:
self.log.warning(
f"Got outdated info when syncing through {source.username} "
f"({info.revision} < {self.revision}), ignoring..."
)
return
changed = await self._update_name(info.title) or changed
changed = await self._update_topic(info.description) or changed
elif isinstance(info, GroupV2ID):
if self.revision < info.revision:
self.revision = info.revision
changed = True
elif self.revision > info.revision:
self.log.warning(
f"Got outdated info when syncing through {source.username} "
f"({info.revision} < {self.revision}), ignoring..."
)
return
else:
raise ValueError(f"Unexpected type for group update_info: {type(info)}")
changed = await self._update_name(info.title) or changed
changed = await self._update_topic(info.description) or changed
changed = await self._update_avatar(info) or changed
await self._update_participants(source, info)
try:
Expand Down Expand Up @@ -2039,12 +2031,10 @@ async def _try_with_puppet(
else:
await action(self.main_intent)

async def _update_avatar(self, info: ChatInfo, sender: p.Puppet | None = None) -> bool:
async def _update_avatar(self, info: GroupV2, sender: p.Puppet | None = None) -> bool:
path = None
if isinstance(info, GroupV2):
path = info.avatar
elif isinstance(info, Group):
path = f"group-{self.chat_id}"
res = await p.Puppet.upload_avatar(self, path, self.main_intent)
if res is False:
return False
Expand All @@ -2062,8 +2052,8 @@ async def _update_avatar(self, info: ChatInfo, sender: p.Puppet | None = None) -
self.avatar_set = False
return True

async def _update_participants(self, source: u.User, info: ChatInfo) -> None:
if not self.mxid or not isinstance(info, (Group, GroupV2)):
async def _update_participants(self, source: u.User, info: GroupV2) -> None:
if not self.mxid:
return

member_events = await self.main_intent.get_members(self.mxid)
Expand All @@ -2083,12 +2073,9 @@ async def _update_participants(self, source: u.User, info: ChatInfo) -> None:
if evt.content.membership == Membership.BAN and evt.state_key != self.az.bot_mxid
}

pending_members = info.pending_members if isinstance(info, GroupV2) else []
requesting_members = info.requesting_members if isinstance(info, GroupV2) else []
banned_members = info.banned_members if isinstance(info, GroupV2) else []
self._pending_members = {addr.uuid for addr in pending_members}
self._pending_members = {addr.uuid for addr in info.pending_members}

for member in banned_members:
for member in info.banned_members:
user = await u.User.get_by_uuid(member.uuid)
if user:
unban_users.discard(user.mxid)
Expand Down Expand Up @@ -2125,7 +2112,7 @@ async def _update_participants(self, source: u.User, info: ChatInfo) -> None:
except (MForbidden, MBadState) as e:
self.log.debug(f"Could not unban {puppet.mxid}: {e}")

for address in info.members + pending_members:
for address in info.members + info.pending_members:
user = await u.User.get_by_address(address)
if user:
remove_users.discard(user.mxid)
Expand All @@ -2138,10 +2125,7 @@ async def _update_participants(self, source: u.User, info: ChatInfo) -> None:
if not puppet:
self.log.warning(f"Didn't find puppet for member {address}")
continue
try:
await source.sync_contact(address)
except ProfileUnavailableError:
self.log.debug(f"Profile of puppet with {address} is unavailable")
await source.sync_contact(address)
try:
await self.main_intent.invite_user(
self.mxid, puppet.intent_for(self).mxid, check_cache=True
Expand All @@ -2152,7 +2136,7 @@ async def _update_participants(self, source: u.User, info: ChatInfo) -> None:
await puppet.intent_for(self).ensure_joined(self.mxid)
remove_users.discard(puppet.default_mxid)

for address in requesting_members:
for address in info.requesting_members:
puppet = await p.Puppet.get_by_address(address)
if puppet:
remove_users.discard(puppet.mxid)
Expand Down Expand Up @@ -2230,7 +2214,7 @@ async def _get_new_join_rule(self, link_access: AccessControlMode) -> JoinRule |
return None
return join_rule

async def _update_join_rules(self, info: ChatInfo) -> None:
async def _update_join_rules(self, info: GroupV2) -> None:
if not self.mxid:
return
new_join_rule = await self._get_new_join_rule(info.access_control.link)
Expand Down Expand Up @@ -2285,7 +2269,7 @@ async def update_bridge_info(self) -> None:
# region Creating Matrix rooms

async def update_matrix_room(self, source: u.User, info: ChatInfo) -> None:
if not self.is_direct and not isinstance(info, (Group, GroupV2, GroupV2ID)):
if not self.is_direct and not isinstance(info, GroupV2):
raise ValueError(f"Unexpected type for updating group portal: {type(info)}")
elif self.is_direct and not isinstance(info, (Profile, Address)):
raise ValueError(f"Unexpected type for updating direct chat portal: {type(info)}")
Expand All @@ -2294,21 +2278,14 @@ async def update_matrix_room(self, source: u.User, info: ChatInfo) -> None:
except Exception:
self.log.exception("Failed to update portal")

async def create_matrix_room(self, source: u.User, info: ChatInfo) -> RoomID | None:
if not self.is_direct and not isinstance(info, (Group, GroupV2, GroupV2ID)):
async def create_matrix_room(
self, source: u.User, info: ChatInfo | GroupV2ID
) -> RoomID | None:
if not self.is_direct and not isinstance(info, GroupV2ID):
raise ValueError(f"Unexpected type for creating group portal: {type(info)}")
elif self.is_direct and not isinstance(info, (Profile, Address)):
raise ValueError(f"Unexpected type for creating direct chat portal: {type(info)}")
if isinstance(info, Group) and not info.members:
try:
groups = await self.signal.list_groups(source.username)
except Exception as e:
await source.handle_auth_failure(e)
raise
info = next(
(g for g in groups if isinstance(g, Group) and g.group_id == info.group_id), info
)
elif isinstance(info, GroupV2ID) and not isinstance(info, GroupV2):
if isinstance(info, GroupV2ID) and not isinstance(info, GroupV2):
self.log.debug(
f"create_matrix_room() called with {info}, fetching full info from signald"
)
Expand Down Expand Up @@ -2367,31 +2344,33 @@ async def _get_power_levels(
levels.state_default = 0
meta_edit_level = 0
else:
if isinstance(info, GroupV2):
ac = info.access_control
for detail in info.member_detail + info.pending_member_detail:
puppet = await p.Puppet.get_by_uuid(detail.uuid)
puppet_mxid = puppet.intent_for(self).mxid
current_level = levels.get_user_level(puppet_mxid)
if bot_pl > current_level and bot_pl >= 50:
level = current_level
if puppet.is_real_user:
if current_level >= 50 and detail.role == GroupMemberRole.DEFAULT:
level = 0
elif (
current_level < 50 and detail.role == GroupMemberRole.ADMINISTRATOR
):
level = 50
else:
level = 50 if detail.role == GroupMemberRole.ADMINISTRATOR else 0
if not info:
self.log.debug(f"No info provided for updating power levels in {self.mxid}")
return
Comment on lines +2347 to +2349
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning None from here is not allowed, but the case seems pointless anyway since info is always provided.

ac = info.access_control
for detail in info.member_detail + info.pending_member_detail:
puppet = await p.Puppet.get_by_uuid(detail.uuid)
puppet_mxid = puppet.intent_for(self).mxid
current_level = levels.get_user_level(puppet_mxid)
if bot_pl > current_level and bot_pl >= 50:
level = current_level
user = await u.User.get_by_uuid(detail.uuid)
if user:
if current_level >= 50 and detail.role == GroupMemberRole.DEFAULT:
level = 0
elif current_level < 50 and detail.role == GroupMemberRole.ADMINISTRATOR:
level = 50
if level == 0:
levels.users.pop(puppet_mxid, None)
levels.users.pop(user.mxid, None)
else:
levels.users[puppet_mxid] = level
announcements = info.announcements
else:
ac = GroupAccessControl()
announcements = AnnouncementsMode.UNKNOWN
levels.users[user.mxid] = level
else:
level = 50 if detail.role == GroupMemberRole.ADMINISTRATOR else 0
if level == 0:
levels.users.pop(puppet_mxid, None)
else:
levels.users[puppet_mxid] = level
announcements = info.announcements
levels.ban = 50
levels.kick = 50
levels.invite = 50 if ac.members == AccessControlMode.ADMINISTRATOR else 0
Expand Down
8 changes: 1 addition & 7 deletions mautrix_signal/signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,6 @@ async def _handle_message(
return
if msg.group_v2:
portal = await po.Portal.get_by_chat_id(msg.group_v2.id, create=True)
elif msg.group:
portal = await po.Portal.get_by_chat_id(msg.group.group_id, create=True)
else:
if addr_override and not addr_override.uuid:
target = await pu.Puppet.get_by_address(addr_override, resolve_via=user.username)
Expand Down Expand Up @@ -237,9 +235,7 @@ async def _handle_message(
" probably not bridgeable as there's no portal yet"
)
return
await portal.create_matrix_room(
user, msg.group_v2 or msg.group or addr_override or sender.address
)
await portal.create_matrix_room(user, msg.group_v2 or addr_override or sender.address)
if not portal.mxid:
user.log.warning(
f"Failed to create room for incoming message {msg.timestamp}, dropping message"
Expand Down Expand Up @@ -267,8 +263,6 @@ async def _handle_message(
await portal.handle_signal_reaction(sender, msg.reaction, msg.timestamp)
if msg.is_message:
await portal.handle_signal_message(user, sender, msg)
if msg.group and msg.group.type == "UPDATE":
await portal.update_info(user, msg.group)
if msg.remote_delete:
await portal.handle_signal_delete(sender, msg.remote_delete.target_sent_timestamp)

Expand Down
1 change: 0 additions & 1 deletion mautrix_signal/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from mausignald.types import (
Account,
Address,
Group,
GroupV2,
Profile,
WebsocketConnectionState,
Expand Down