From 177b164b6a1fb8cf3a69f587047ccee9d769d722 Mon Sep 17 00:00:00 2001 From: Malte E Date: Fri, 16 Aug 2024 21:26:02 +0200 Subject: [PATCH 1/2] v2: matrix -> signal power levels --- pkg/connector/handlematrix.go | 89 +++++++++++++++++++++++++++++------ pkg/signalid/ids.go | 10 ++++ 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 888d702b..93e4505e 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -359,20 +359,17 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 return false, nil } } - if msg.TargetGhost != nil { - targetIntent = msg.TargetGhost.Intent - targetSignalID, err = signalid.ParseUserID(msg.TargetGhost.ID) - if err != nil { - return false, fmt.Errorf("failed to parse target ghost signal id: %w", err) - } - } else if msg.TargetUserLogin != nil { - targetSignalID, err = signalid.ParseUserLoginID(msg.TargetUserLogin.ID) - if err != nil { - return false, fmt.Errorf("failed to parse target user signal id: %w", err) - } - targetIntent = msg.TargetUserLogin.User.DoublePuppet(ctx) + targetSignalID, err = signalid.ParseGhostOrUserLoginID(msg.Target) + if err != nil { + return false, fmt.Errorf("failed to parse target signal id: %w", err) + } + if ghost, ok := msg.Target.(*bridgev2.Ghost); ok { + targetIntent = ghost.Intent + } else { + userLogin, _ := msg.Target.(*bridgev2.UserLogin) + targetIntent = userLogin.User.DoublePuppet(ctx) if targetIntent == nil { - ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(msg.TargetUserLogin.ID)) + ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(userLogin.ID)) if err != nil { return false, fmt.Errorf("failed to get ghost for user: %w", err) } @@ -389,7 +386,7 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 levels, err := msg.Portal.Bridge.Matrix.GetPowerLevels(ctx, msg.Portal.MXID) if err != nil { log.Err(err).Msg("Couldn't get power levels") - if levels.GetUserLevel(targetIntent.GetMXID()) >= 50 { + if levels.GetUserLevel(targetIntent.GetMXID()) >= moderatorPL { role = signalmeow.GroupMember_ADMINISTRATOR } } @@ -472,3 +469,67 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision return true, nil } + +func plToRole(pl int) signalmeow.GroupMemberRole { + if pl >= moderatorPL { + return signalmeow.GroupMember_ADMINISTRATOR + } else { + return signalmeow.GroupMember_DEFAULT + } +} + +func hasAdminChanged(plc *bridgev2.SinglePowerLevelChange) bool { + if plc == nil { + return false + } + return (plc.NewLevel < moderatorPL) != (plc.OrigLevel < moderatorPL) +} + +func (s *SignalClient) HandleMatrixPowerLevels(ctx context.Context, msg *bridgev2.MatrixPowerLevelChange) (bool, error) { + if msg.Portal.RoomType == database.RoomTypeDM { + return false, nil + } + log := zerolog.Ctx(ctx) + gc := &signalmeow.GroupChange{} + for _, plc := range msg.Users { + if !hasAdminChanged(&plc.SinglePowerLevelChange) { + continue + } + aci, err := signalid.ParseGhostOrUserLoginID(plc.Target) + if err != nil { + log.Err(err).Msg("Couldn't parse user id") + } + gc.ModifyMemberRoles = append(gc.ModifyMemberRoles, &signalmeow.RoleMember{ + ACI: aci, + Role: plToRole(plc.NewLevel), + }) + } + if hasAdminChanged(msg.EventsDefault) { + announcementsOnly := msg.EventsDefault.NewLevel >= moderatorPL + gc.ModifyAnnouncementsOnly = &announcementsOnly + } + if hasAdminChanged(msg.StateDefault) { + attributesAccess := signalmeow.AccessControl_MEMBER + if msg.StateDefault.NewLevel >= moderatorPL { + attributesAccess = signalmeow.AccessControl_ADMINISTRATOR + } + gc.ModifyAttributesAccess = &attributesAccess + } + if hasAdminChanged(msg.Invite) { + memberAccess := signalmeow.AccessControl_MEMBER + if msg.Invite.NewLevel >= moderatorPL { + memberAccess = signalmeow.AccessControl_ADMINISTRATOR + } + gc.ModifyMemberAccess = &memberAccess + } + _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) + if err != nil || groupID == "" { + return false, err + } + revision, err := s.Client.UpdateGroup(ctx, gc, groupID) + if err != nil { + return false, err + } + msg.Portal.Metadata.(*signalid.PortalMetadata).Revision = revision + return true, nil +} diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go index 99ef7b3e..7181e935 100644 --- a/pkg/signalid/ids.go +++ b/pkg/signalid/ids.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/google/uuid" + "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "go.mau.fi/mautrix-signal/pkg/libsignalgo" @@ -47,6 +48,15 @@ func ParseUserLoginID(userLoginID networkid.UserLoginID) (uuid.UUID, error) { return userID, nil } +func ParseGhostOrUserLoginID(ghostOrUserLogin bridgev2.GhostOrUserLogin) (uuid.UUID, error) { + if userLogin, ok := ghostOrUserLogin.(*bridgev2.UserLogin); ok { + return ParseUserLoginID(userLogin.ID) + } else { + ghost, _ := ghostOrUserLogin.(*bridgev2.Ghost) + return ParseUserID(ghost.ID) + } +} + func ParseUserIDAsServiceID(userID networkid.UserID) (libsignalgo.ServiceID, error) { return libsignalgo.ServiceIDFromString(string(userID)) } From 094a819720090988a5dce7e7ea54a4c158826432 Mon Sep 17 00:00:00 2001 From: Malte E Date: Fri, 16 Aug 2024 22:01:40 +0200 Subject: [PATCH 2/2] switchcase, helper function --- pkg/connector/handlematrix.go | 36 +++++++++++++++++++---------------- pkg/signalid/ids.go | 12 +++++++----- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 93e4505e..8a973ebb 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -363,18 +363,20 @@ func (s *SignalClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2 if err != nil { return false, fmt.Errorf("failed to parse target signal id: %w", err) } - if ghost, ok := msg.Target.(*bridgev2.Ghost); ok { - targetIntent = ghost.Intent - } else { - userLogin, _ := msg.Target.(*bridgev2.UserLogin) - targetIntent = userLogin.User.DoublePuppet(ctx) + switch target := msg.Target.(type) { + case *bridgev2.Ghost: + targetIntent = target.Intent + case *bridgev2.UserLogin: + targetIntent = target.User.DoublePuppet(ctx) if targetIntent == nil { - ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(userLogin.ID)) + ghost, err := s.Main.Bridge.GetGhostByID(ctx, networkid.UserID(target.ID)) if err != nil { return false, fmt.Errorf("failed to get ghost for user: %w", err) } targetIntent = ghost.Intent } + default: + return false, fmt.Errorf("cannot get target intent: unknown type: %T", target) } log := zerolog.Ctx(ctx).With(). Str("From Membership", string(msg.Type.From)). @@ -478,6 +480,16 @@ func plToRole(pl int) signalmeow.GroupMemberRole { } } +func plToAccessControl(pl int) *signalmeow.AccessControl { + var accessControl signalmeow.AccessControl + if pl >= moderatorPL { + accessControl = signalmeow.AccessControl_ADMINISTRATOR + } else { + accessControl = signalmeow.AccessControl_MEMBER + } + return &accessControl +} + func hasAdminChanged(plc *bridgev2.SinglePowerLevelChange) bool { if plc == nil { return false @@ -509,18 +521,10 @@ func (s *SignalClient) HandleMatrixPowerLevels(ctx context.Context, msg *bridgev gc.ModifyAnnouncementsOnly = &announcementsOnly } if hasAdminChanged(msg.StateDefault) { - attributesAccess := signalmeow.AccessControl_MEMBER - if msg.StateDefault.NewLevel >= moderatorPL { - attributesAccess = signalmeow.AccessControl_ADMINISTRATOR - } - gc.ModifyAttributesAccess = &attributesAccess + gc.ModifyAttributesAccess = plToAccessControl(msg.StateDefault.NewLevel) } if hasAdminChanged(msg.Invite) { - memberAccess := signalmeow.AccessControl_MEMBER - if msg.Invite.NewLevel >= moderatorPL { - memberAccess = signalmeow.AccessControl_ADMINISTRATOR - } - gc.ModifyMemberAccess = &memberAccess + gc.ModifyMemberAccess = plToAccessControl(msg.Invite.NewLevel) } _, groupID, err := signalid.ParsePortalID(msg.Portal.ID) if err != nil || groupID == "" { diff --git a/pkg/signalid/ids.go b/pkg/signalid/ids.go index 7181e935..ec002ce7 100644 --- a/pkg/signalid/ids.go +++ b/pkg/signalid/ids.go @@ -49,11 +49,13 @@ func ParseUserLoginID(userLoginID networkid.UserLoginID) (uuid.UUID, error) { } func ParseGhostOrUserLoginID(ghostOrUserLogin bridgev2.GhostOrUserLogin) (uuid.UUID, error) { - if userLogin, ok := ghostOrUserLogin.(*bridgev2.UserLogin); ok { - return ParseUserLoginID(userLogin.ID) - } else { - ghost, _ := ghostOrUserLogin.(*bridgev2.Ghost) - return ParseUserID(ghost.ID) + switch ghostOrUserLogin := ghostOrUserLogin.(type) { + case *bridgev2.UserLogin: + return ParseUserLoginID(ghostOrUserLogin.ID) + case *bridgev2.Ghost: + return ParseUserID(ghostOrUserLogin.ID) + default: + return uuid.Nil, fmt.Errorf("cannot parse ID: unknown type: %T", ghostOrUserLogin) } }