diff --git a/commands.go b/commands.go index 8e605ba8..2f224bc3 100644 --- a/commands.go +++ b/commands.go @@ -71,6 +71,9 @@ func (br *SignalBridge) RegisterCommands() { cmdInviteLink, cmdResetInviteLink, cmdCreate, + cmdInvite, + cmdListInvited, + cmdRevokeInvite, ) } @@ -284,6 +287,218 @@ func fnPM(ce *WrappedCommandEvent) { } } +var cmdInvite = &commands.FullHandler{ + Func: wrapCommand(fnInvite), + Name: "invite", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "Invite a user by phone number.", + Args: "<_international phone number_>", + }, + RequiresLogin: true, + RequiresPortal: true, +} + +func fnInvite(ce *WrappedCommandEvent) { + if len(ce.Args) == 0 { + ce.Reply("**Usage:** `invite `") + return + } + number, err := strconv.ParseUint(numberCleaner.Replace(strings.Join(ce.Args, "")), 10, 64) + if err != nil { + ce.Reply("Failed to parse number") + return + } + + user := ce.User + var aci, pni uuid.UUID + e164 := fmt.Sprintf("+%d", number) + var recipient *types.Recipient + + if recipient, err = user.Client.ContactByE164(ce.Ctx, e164); err != nil { + ce.Reply("Error looking up number in local contact list: %v", err) + return + } else if recipient != nil && (recipient.ACI != uuid.Nil || recipient.PNI != uuid.Nil) { + // TODO maybe lookup PNI if there's only ACI and E164 stored? + aci = recipient.ACI + pni = recipient.PNI + } else if resp, err := user.Client.LookupPhone(ce.Ctx, number); err != nil { + ce.ZLog.Err(err).Uint64("e164", number).Msg("Failed to lookup number on server") + ce.Reply("Error looking up number on server: %v", err) + return + } else { + aci = resp[number].ACI + pni = resp[number].PNI + if aci == uuid.Nil && pni == uuid.Nil { + ce.Reply("+%d doesn't seem to be on Signal", number) + return + } + recipient, err = user.Client.Store.RecipientStore.UpdateRecipientE164(ce.Ctx, aci, pni, e164) + if err != nil { + ce.ZLog.Err(err).Msg("Failed to save recipient entry after looking up phone") + } + aci, pni = recipient.ACI, recipient.PNI + } + ce.ZLog.Debug(). + Uint64("e164", number). + Stringer("aci", aci). + Stringer("pni", pni). + Msg("Found Invite target user") + + var groupChange signalmeow.GroupChange + if aci != uuid.Nil { + groupChange.AddMembers = []*signalmeow.AddMember{ + { + GroupMember: signalmeow.GroupMember{ + ACI: aci, + Role: signalmeow.GroupMember_DEFAULT, + }, + }, + } + } else { + groupChange.AddPendingMembers = []*signalmeow.PendingMember{ + { + ServiceID: libsignalgo.NewPNIServiceID(pni), + AddedByUserID: ce.User.SignalID, + Role: signalmeow.GroupMember_DEFAULT, + }, + } + } + revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) + if err != nil { + ce.Reply("Failed to update group: %w", err) + return + } + ce.Portal.Revision = revision + if aci != uuid.Nil { + group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), revision) + if err != nil { + ce.Reply("Failed to fetch group after invite: %w", err) + } + ce.Portal.SyncParticipants(ce.Ctx, user, group) + ce.Portal.Update(ce.Ctx) + return + } + ce.Portal.Update(ce.Ctx) + ce.Reply("Invited " + e164) +} + +var cmdListInvited = &commands.FullHandler{ + Func: wrapCommand(fnListInvited), + Name: "list-invited", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "list pending invites", + Args: "<_international phone number_>", + }, + RequiresLogin: true, + RequiresPortal: true, +} + +func fnListInvited(ce *WrappedCommandEvent) { + group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), ce.Portal.Revision) + if err != nil { + ce.Reply("Failed to fetch group info: %w", err) + return + } + var memberList []string + for _, pendingMember := range group.PendingMembers { + recipientString, err := pendingMemberToString(ce.Ctx, ce.User, pendingMember) + if err != nil { + ce.Reply("Failed to fetch recipient for %s: %w", pendingMember.ServiceID, err) + continue + } + memberList = append(memberList, recipientString) + } + if len(memberList) == 0 { + ce.Reply("No pending Invites") + } else { + ce.Reply(strings.Join(memberList, "\n")) + } +} + +func pendingMemberToString(ctx context.Context, user *User, pendingMember *signalmeow.PendingMember) (string, error) { + var pni, aci uuid.UUID + if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypeACI { + aci = pendingMember.ServiceID.UUID + } else { + pni = pendingMember.ServiceID.UUID + } + recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, nil) + if err != nil { + return "", err + } + if recipient.E164 != "" { + return recipient.E164, nil + } else { + return "Unidentified User", nil + } +} + +var cmdRevokeInvite = &commands.FullHandler{ + Func: wrapCommand(fnRevokeInvite), + Name: "revoke-invite", + Help: commands.HelpMeta{ + Section: HelpSectionPortalManagement, + Description: "Revoke an invite by phone number.", + Args: "<_international phone number_>", + }, + RequiresLogin: true, + RequiresPortal: true, +} + +func fnRevokeInvite(ce *WrappedCommandEvent) { + if len(ce.Args) == 0 { + ce.Reply("**Usage:** `RevokeInvite `") + return + } + e164 := "+" + numberCleaner.Replace(strings.Join(ce.Args, "")) + + user := ce.User + var serviceID libsignalgo.ServiceID + group, err := ce.User.Client.RetrieveGroupByID(ce.Ctx, ce.Portal.GroupID(), ce.Portal.Revision) + if err != nil { + ce.Reply("Failed to fetch group info: %w", err) + return + } + var pni, aci uuid.UUID + for _, pendingMember := range group.PendingMembers { + if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypeACI { + aci = pendingMember.ServiceID.UUID + } else { + pni = pendingMember.ServiceID.UUID + } + recipient, err := user.Client.Store.RecipientStore.LoadAndUpdateRecipient(ce.Ctx, aci, pni, nil) + if err != nil { + continue + } + if recipient.E164 == e164 { + serviceID = pendingMember.ServiceID + break + } + } + if serviceID.UUID == uuid.Nil { + ce.Reply("User not in Group") + return + } + var groupChange signalmeow.GroupChange + groupChange.DeletePendingMembers = []*libsignalgo.ServiceID{&serviceID} + revision, err := ce.User.Client.UpdateGroup(ce.Ctx, &groupChange, ce.Portal.GroupID()) + if err != nil { + ce.Reply("Failed to update group: %w", err) + return + } + if aci != uuid.Nil { + target := ce.Bridge.GetPuppetBySignalID(aci) + if target != nil { + ce.Bot.SendCustomMembershipEvent(ce.Ctx, ce.Portal.MXID, target.IntentFor(ce.Portal).UserID, event.MembershipLeave, "removed by "+user.MXID.String()) + } + } + ce.Portal.Revision = revision + ce.Portal.Update(ce.Ctx) + ce.Reply("Revoked the invitation for " + e164) +} + var cmdResolvePhone = &commands.FullHandler{ Func: wrapCommand(fnResolvePhone), Name: "resolve-phone", @@ -822,12 +1037,12 @@ func fnCreate(ce *WrappedCommandEvent) { // joined members that need to be pending-Members should have their signal invite auto-accepted if membership == event.MembershipJoin || membership == event.MembershipInvite { participants = append(participants, &signalmeow.GroupMember{ - UserID: uuid, - Role: role, + ACI: uuid, + Role: role, }) } else if membership == event.MembershipBan { bannedMembers = append(bannedMembers, &signalmeow.BannedMember{ - UserID: uuid, + ServiceID: libsignalgo.NewACIServiceID(uuid), }) } } diff --git a/pkg/libsignalgo/groupsecretparams.go b/pkg/libsignalgo/groupsecretparams.go index fed5477f..76a28f7f 100644 --- a/pkg/libsignalgo/groupsecretparams.go +++ b/pkg/libsignalgo/groupsecretparams.go @@ -23,7 +23,6 @@ package libsignalgo import "C" import ( "crypto/rand" - "fmt" "runtime" "unsafe" @@ -139,41 +138,36 @@ func (gsp *GroupSecretParams) EncryptBlobWithPaddingDeterministic(randomness Ran return CopySignalOwnedBufferToBytes(ciphertext), nil } -func (gsp *GroupSecretParams) DecryptUUID(ciphertextUUID UUIDCiphertext) (uuid.UUID, error) { - // TODO this should probably be DecryptServiceID - +func (gsp *GroupSecretParams) DecryptServiceID(ciphertextServiceID UUIDCiphertext) (ServiceID, error) { u := C.SignalServiceIdFixedWidthBinaryBytes{} signalFfiError := C.signal_group_secret_params_decrypt_service_id( &u, (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)), - (*[C.SignalUUID_CIPHERTEXT_LEN]C.uint8_t)(unsafe.Pointer(&ciphertextUUID)), + (*[C.SignalUUID_CIPHERTEXT_LEN]C.uint8_t)(unsafe.Pointer(&ciphertextServiceID)), ) runtime.KeepAlive(gsp) - runtime.KeepAlive(ciphertextUUID) + runtime.KeepAlive(ciphertextServiceID) if signalFfiError != nil { - return uuid.Nil, wrapError(signalFfiError) + return EmptyServiceID, wrapError(signalFfiError) } serviceID := ServiceIDFromCFixedBytes(&u) - if serviceID.Type != ServiceIDTypeACI { - return uuid.Nil, fmt.Errorf("unexpected service ID type %d", serviceID.Type) - } - return serviceID.UUID, nil + return serviceID, nil } -func (gsp *GroupSecretParams) EncryptUUID(uuid uuid.UUID) (*UUIDCiphertext, error) { - var cipherTextUUID [C.SignalUUID_CIPHERTEXT_LEN]C.uchar +func (gsp *GroupSecretParams) EncryptServiceID(serviceID ServiceID) (*UUIDCiphertext, error) { + var cipherTextServiceID [C.SignalUUID_CIPHERTEXT_LEN]C.uchar signalFfiError := C.signal_group_secret_params_encrypt_service_id( - &cipherTextUUID, + &cipherTextServiceID, (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)), - NewACIServiceID(uuid).CFixedBytes(), + serviceID.CFixedBytes(), ) runtime.KeepAlive(gsp) if signalFfiError != nil { return nil, wrapError(signalFfiError) } var result UUIDCiphertext - copy(result[:], C.GoBytes(unsafe.Pointer(&cipherTextUUID), C.int(C.SignalUUID_CIPHERTEXT_LEN))) + copy(result[:], C.GoBytes(unsafe.Pointer(&cipherTextServiceID), C.int(C.SignalUUID_CIPHERTEXT_LEN))) return &result, nil } diff --git a/pkg/signalmeow/groups.go b/pkg/signalmeow/groups.go index e789ff48..829fc03b 100644 --- a/pkg/signalmeow/groups.go +++ b/pkg/signalmeow/groups.go @@ -65,15 +65,14 @@ const ( ) type GroupMember struct { - UserID uuid.UUID + ACI uuid.UUID Role GroupMemberRole ProfileKey libsignalgo.ProfileKey JoinedAtRevision uint32 - //Presentation []byte } func (gm *GroupMember) UserServiceID() libsignalgo.ServiceID { - return libsignalgo.NewACIServiceID(gm.UserID) + return libsignalgo.NewACIServiceID(gm.ACI) } type Group struct { @@ -138,38 +137,41 @@ type AddMember struct { } type PendingMember struct { - GroupMember + ServiceID libsignalgo.ServiceID + Role GroupMemberRole AddedByUserID uuid.UUID Timestamp uint64 } type ProfileKeyMember struct { - UserID uuid.UUID + ACI uuid.UUID ProfileKey libsignalgo.ProfileKey - //Presentation []byte } type RequestingMember struct { - UserID uuid.UUID + ACI uuid.UUID ProfileKey libsignalgo.ProfileKey Timestamp uint64 - //Presentation []byte } -// type PromotePniAciMember struct { -// UserID uuid.UUID -// ProfileKey libsignalgo.ProfileKey -// PNI uuid.UUID -// Presentation []byte -// } +type PromotePendingMembers struct { + ACI uuid.UUID + ProfileKey libsignalgo.ProfileKey +} + +type PromotePendingPniAciMember struct { + ACI uuid.UUID + ProfileKey libsignalgo.ProfileKey + PNI uuid.UUID +} type RoleMember struct { - UserID uuid.UUID - Role GroupMemberRole + ACI uuid.UUID + Role GroupMemberRole } type BannedMember struct { - UserID uuid.UUID + ServiceID libsignalgo.ServiceID Timestamp uint64 } @@ -182,8 +184,8 @@ type GroupChange struct { ModifyMemberRoles []*RoleMember ModifyMemberProfileKeys []*ProfileKeyMember AddPendingMembers []*PendingMember - DeletePendingMembers []*uuid.UUID - PromotePendingMembers []*ProfileKeyMember + DeletePendingMembers []*libsignalgo.ServiceID + PromotePendingMembers []*GroupMember ModifyTitle *string ModifyAvatar *string ModifyDisappearingMessagesDuration *uint32 @@ -196,8 +198,8 @@ type GroupChange struct { ModifyDescription *string ModifyAnnouncementsOnly *bool AddBannedMembers []*BannedMember - DeleteBannedMembers []*uuid.UUID - PromotePendingPniAciMembers []*ProfileKeyMember + DeleteBannedMembers []*libsignalgo.ServiceID + PromotePendingPniAciMembers []*PromotePendingPniAciMember ModifyInviteLinkPassword *types.SerializedInviteLinkPassword } @@ -250,38 +252,38 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } members := make(map[uuid.UUID]GroupMemberRole) for _, member := range group.Members { - members[member.UserID] = member.Role + members[member.ACI] = member.Role } - pendingMembers := make(map[uuid.UUID]bool) + pendingMembers := make(map[libsignalgo.ServiceID]bool) for _, pendingMember := range group.PendingMembers { - pendingMembers[pendingMember.UserID] = true + pendingMembers[pendingMember.ServiceID] = true } requestingMembers := make(map[uuid.UUID]bool) for _, requestingMember := range group.RequestingMembers { - requestingMembers[requestingMember.UserID] = true + requestingMembers[requestingMember.ACI] = true } for i, member := range groupChange.AddMembers { - if _, ok := members[member.GroupMember.UserID]; ok { + if _, ok := members[member.GroupMember.ACI]; ok { groupChange.AddMembers = append(groupChange.AddMembers[:i], groupChange.AddMembers[i+1:]...) } } for i, promotePendingMember := range groupChange.PromotePendingMembers { - if _, ok := members[promotePendingMember.UserID]; ok { + if _, ok := members[promotePendingMember.ACI]; ok { groupChange.PromotePendingMembers = append(groupChange.PromotePendingMembers[:i], groupChange.PromotePendingMembers[i+1:]...) } } for i, promoteRequestingMember := range groupChange.PromotePendingMembers { - if _, ok := members[promoteRequestingMember.UserID]; ok { + if _, ok := members[promoteRequestingMember.ACI]; ok { groupChange.PromoteRequestingMembers = append(groupChange.PromoteRequestingMembers[:i], groupChange.PromoteRequestingMembers[i+1:]...) } } for i, pendingMember := range groupChange.AddPendingMembers { - if pendingMembers[pendingMember.GroupMember.UserID] { + if pendingMembers[pendingMember.ServiceID] { groupChange.AddPendingMembers = append(groupChange.AddPendingMembers[:i], groupChange.AddPendingMembers[i+1:]...) } } for i, requestingMember := range groupChange.AddRequestingMembers { - if pendingMembers[requestingMember.UserID] { + if requestingMembers[requestingMember.ACI] { groupChange.AddRequestingMembers = append(groupChange.AddRequestingMembers[:i], groupChange.AddRequestingMembers[i+1:]...) } } @@ -291,7 +293,7 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } } for i, deleteRequestingMember := range groupChange.DeleteRequestingMembers { - if !pendingMembers[*deleteRequestingMember] { + if !requestingMembers[*deleteRequestingMember] { groupChange.DeleteRequestingMembers = append(groupChange.DeleteRequestingMembers[:i], groupChange.DeleteRequestingMembers[i+1:]...) } } @@ -301,7 +303,7 @@ func (groupChange *GroupChange) resolveConflict(group *Group) { } } for i, modifyMemberRole := range groupChange.ModifyMemberRoles { - if members[modifyMemberRole.UserID] == modifyMemberRole.Role { + if members[modifyMemberRole.ACI] == modifyMemberRole.Role { groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles[:i], groupChange.ModifyMemberRoles[i+1:]...) } } @@ -563,13 +565,13 @@ func decryptGroup(ctx context.Context, encryptedGroup *signalpb.Group, groupMast continue } encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error") return nil, err } decryptedGroup.BannedMembers = append(decryptedGroup.BannedMembers, &BannedMember{ - UserID: userID, + ServiceID: serviceID, Timestamp: bannedMember.Timestamp, }) } @@ -697,19 +699,13 @@ func (cli *Client) fetchGroupWithMasterKey(ctx context.Context, groupMasterKey t // Store the profile keys in case they're new for _, member := range group.Members { - err = cli.Store.RecipientStore.StoreProfileKey(ctx, member.UserID, member.ProfileKey) - if err != nil { - return nil, fmt.Errorf("failed to store profile key: %w", err) - } - } - for _, pendingMember := range group.PendingMembers { - err = cli.Store.RecipientStore.StoreProfileKey(ctx, pendingMember.UserID, pendingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, member.ACI, member.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } } for _, requestingMember := range group.RequestingMembers { - err = cli.Store.RecipientStore.StoreProfileKey(ctx, requestingMember.UserID, requestingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, requestingMember.ACI, requestingMember.ProfileKey) if err != nil { return nil, fmt.Errorf("failed to store profile key: %w", err) } @@ -884,7 +880,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp GroupMember: *decryptedMember, JoinFromInviteLink: addMember.JoinFromInviteLink, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedMember.UserID, decryptedMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedMember.ACI, decryptedMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -896,24 +892,30 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deleteMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deleteMember") return nil, err } - decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &userID) + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } + decryptedGroupChange.DeleteMembers = append(decryptedGroupChange.DeleteMembers, &serviceID.UUID) } for _, modifyMemberRole := range encryptedActions.ModifyMemberRoles { encryptedUserID := libsignalgo.UUIDCiphertext(modifyMemberRole.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for modifyMemberRole") return nil, err } + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } decryptedGroupChange.ModifyMemberRoles = append(decryptedGroupChange.ModifyMemberRoles, &RoleMember{ - UserID: userID, - Role: GroupMemberRole(modifyMemberRole.Role), + ACI: serviceID.UUID, + Role: GroupMemberRole(modifyMemberRole.Role), }) } @@ -922,22 +924,25 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(modifyProfileKey.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for modifyProfileKey") return nil, err } + if serviceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(modifyProfileKey.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for modifyProfileKey") return nil, err } decryptedGroupChange.ModifyMemberProfileKeys = append(decryptedGroupChange.ModifyMemberProfileKeys, &ProfileKeyMember{ - UserID: userID, + ACI: serviceID.UUID, ProfileKey: *profileKey, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, serviceID.UUID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -962,7 +967,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deletePendingMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deletePendingMember") return nil, err @@ -975,50 +980,63 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for promotePendingMember") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingMember") return nil, err } - decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ - UserID: userID, + decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &GroupMember{ + ACI: serviceID.UUID, ProfileKey: *profileKey, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, serviceID.UUID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err } } - for _, promotePendingMember := range encryptedActions.PromotePendingPniAciMembers { + for _, promotePendingPniAciMember := range encryptedActions.PromotePendingPniAciMembers { // TODO: pretending this is a PendingMember should do for mautrix-signal, but we probably want to treat them separately at some point - if promotePendingMember == nil { + if promotePendingPniAciMember == nil { continue } - encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + encryptedUserID := libsignalgo.UUIDCiphertext(promotePendingPniAciMember.UserId) + aciServiceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for promotePendingPniAciMember") return nil, err } - encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + if aciServiceID.Type != libsignalgo.ServiceIDTypeACI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected ACI, got PNI") + } + encryptedUserID = libsignalgo.UUIDCiphertext(promotePendingPniAciMember.Pni) + pniServiceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) + if err != nil { + log.Err(err).Msg("DecryptUUID Pni error for promotePendingPniAciMember") + return nil, err + } + if pniServiceID.Type != libsignalgo.ServiceIDTypePNI { + return nil, fmt.Errorf("Wrong ServiceID kind: expected PNI, got ACI") + } + encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(promotePendingPniAciMember.ProfileKey) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, aciServiceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for promotePendingPniAciMember") return nil, err } - decryptedGroupChange.PromotePendingMembers = append(decryptedGroupChange.PromotePendingMembers, &ProfileKeyMember{ - UserID: userID, + decryptedGroupChange.PromotePendingPniAciMembers = append(decryptedGroupChange.PromotePendingPniAciMembers, &PromotePendingPniAciMember{ + ACI: aciServiceID.UUID, ProfileKey: *profileKey, + PNI: pniServiceID.UUID, }) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, userID, *profileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, aciServiceID.UUID, *profileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1034,7 +1052,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp return nil, err } decryptedGroupChange.AddRequestingMembers = append(decryptedGroupChange.AddRequestingMembers, decryptedRequestingMember) - err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedRequestingMember.UserID, decryptedRequestingMember.ProfileKey) + err = cli.Store.RecipientStore.StoreProfileKey(ctx, decryptedRequestingMember.ACI, decryptedRequestingMember.ProfileKey) if err != nil { log.Err(err).Msg("failed to store profile key") return nil, err @@ -1046,12 +1064,12 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deleteRequestingMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deleteRequestingMember") return nil, err } - decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &userID) + decryptedGroupChange.DeleteRequestingMembers = append(decryptedGroupChange.DeleteRequestingMembers, &serviceID.UUID) } for _, promoteRequestingMember := range encryptedActions.PromoteRequestingMembers { @@ -1059,14 +1077,14 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(promoteRequestingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for promoteRequestingMember") return nil, err } decryptedGroupChange.PromoteRequestingMembers = append(decryptedGroupChange.PromoteRequestingMembers, &RoleMember{ - UserID: userID, - Role: GroupMemberRole(promoteRequestingMember.Role), + ACI: serviceID.UUID, + Role: GroupMemberRole(promoteRequestingMember.Role), }) } @@ -1076,13 +1094,13 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp } bannedMember := addBannedMember.Added encryptedUserID := libsignalgo.UUIDCiphertext(bannedMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for addBannedMember") return nil, err } decryptedGroupChange.AddBannedMembers = append(decryptedGroupChange.AddBannedMembers, &BannedMember{ - UserID: userID, + ServiceID: serviceID, Timestamp: bannedMember.Timestamp, }) } @@ -1092,7 +1110,7 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp continue } encryptedUserID := libsignalgo.UUIDCiphertext(deleteBannedMember.DeletedUserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for deleteBannedMember") return nil, err @@ -1134,19 +1152,19 @@ func (cli *Client) DecryptGroupChange(ctx context.Context, groupContext *signalp func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretParams libsignalgo.GroupSecretParams) (*GroupMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(member.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(member.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error") return nil, err } return &GroupMember{ - UserID: userID, + ACI: serviceID.UUID, ProfileKey: *profileKey, Role: GroupMemberRole(member.Role), JoinedAtRevision: member.JoinedAtRevision, @@ -1156,25 +1174,22 @@ func decryptMember(ctx context.Context, member *signalpb.Member, groupSecretPara func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMember, groupSecretParams libsignalgo.GroupSecretParams) (*PendingMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(pendingMember.Member.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + userID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for pendingMember") return nil, err } // pendingMembers don't have profile keys encryptedAddedByUserID := pendingMember.AddedByUserId - addedByUserId, err := groupSecretParams.DecryptUUID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) + addedByServiceId, err := groupSecretParams.DecryptServiceID(libsignalgo.UUIDCiphertext(encryptedAddedByUserID)) if err != nil { log.Err(err).Msg("DecryptUUID addedByUserId error for pendingMember") return nil, err } return &PendingMember{ - GroupMember: GroupMember{ - UserID: userID, - Role: GroupMemberRole(pendingMember.Member.Role), - JoinedAtRevision: pendingMember.Member.JoinedAtRevision, - }, - AddedByUserID: addedByUserId, + ServiceID: userID, + Role: GroupMemberRole(pendingMember.Member.Role), + AddedByUserID: addedByServiceId.UUID, Timestamp: pendingMember.Timestamp, }, nil } @@ -1182,19 +1197,19 @@ func decryptPendingMember(ctx context.Context, pendingMember *signalpb.PendingMe func decryptRequestingMember(ctx context.Context, requestingMember *signalpb.RequestingMember, groupSecretParams libsignalgo.GroupSecretParams) (*RequestingMember, error) { log := zerolog.Ctx(ctx) encryptedUserID := libsignalgo.UUIDCiphertext(requestingMember.UserId) - userID, err := groupSecretParams.DecryptUUID(encryptedUserID) + serviceID, err := groupSecretParams.DecryptServiceID(encryptedUserID) if err != nil { log.Err(err).Msg("DecryptUUID UserId error for requestingMember") return nil, err } encryptedProfileKey := libsignalgo.ProfileKeyCiphertext(requestingMember.ProfileKey) - profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, userID) + profileKey, err := groupSecretParams.DecryptProfileKey(encryptedProfileKey, serviceID.UUID) if err != nil { log.Err(err).Msg("DecryptProfileKey ProfileKey error for requestingMember") return nil, err } return &RequestingMember{ - UserID: userID, + ACI: serviceID.UUID, ProfileKey: *profileKey, Timestamp: requestingMember.Timestamp, }, nil @@ -1232,17 +1247,23 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup groupChangeActions.ModifyAvatar = &signalpb.GroupChange_Actions_ModifyAvatarAction{Avatar: *decryptedGroupChange.ModifyAvatar} } for _, addMember := range decryptedGroupChange.AddMembers { - encryptedMember, err := cli.encryptMember(ctx, &addMember.GroupMember, &groupSecretParams) + encryptedMember, encryptedPendingMember, err := cli.encryptMember(ctx, &addMember.GroupMember, &groupSecretParams) if err != nil { log.Err(err).Msg("Failed to encrypt GroupMember") } - groupChangeActions.AddMembers = append(groupChangeActions.AddMembers, &signalpb.GroupChange_Actions_AddMemberAction{ - Added: encryptedMember, - JoinFromInviteLink: addMember.JoinFromInviteLink, - }) + if encryptedMember != nil { + groupChangeActions.AddMembers = append(groupChangeActions.AddMembers, &signalpb.GroupChange_Actions_AddMemberAction{ + Added: encryptedMember, + JoinFromInviteLink: addMember.JoinFromInviteLink, + }) + } else { + groupChangeActions.AddPendingMembers = append(groupChangeActions.AddPendingMembers, &signalpb.GroupChange_Actions_AddPendingMemberAction{ + Added: encryptedPendingMember, + }) + } } for _, deleteMember := range decryptedGroupChange.DeleteMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(*deleteMember)) if err != nil { log.Err(err).Msg("Encrypt UserId error for deleteMember") return nil, err @@ -1252,7 +1273,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, modifyMemberRoles := range decryptedGroupChange.ModifyMemberRoles { - encryptedUserID, err := groupSecretParams.EncryptUUID(modifyMemberRoles.UserID) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(modifyMemberRoles.ACI)) if err != nil { log.Err(err).Msg("Encrypt UserId error for modifyMemberRoles") return nil, err @@ -1262,10 +1283,18 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup Role: signalpb.Member_Role(modifyMemberRoles.Role), }) } - // for _, addPendingMember := range decryptedGroupChange.AddPendingMembers { - // } + for _, addPendingMember := range decryptedGroupChange.AddPendingMembers { + encryptedPendingMember, err := cli.encryptPendingMember(ctx, addPendingMember, &groupSecretParams) + if err != nil { + log.Err(err).Msg("Failed to encrypt pendingMember") + return nil, err + } + groupChangeActions.AddPendingMembers = append(groupChangeActions.AddPendingMembers, &signalpb.GroupChange_Actions_AddPendingMemberAction{ + Added: encryptedPendingMember, + }) + } for _, deletePendingMember := range decryptedGroupChange.DeletePendingMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deletePendingMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(*deletePendingMember) if err != nil { log.Err(err).Msg("Encrypt UserId error for deletePendingMember") return nil, err @@ -1275,7 +1304,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, promotePendingMember := range decryptedGroupChange.PromotePendingMembers { - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, promotePendingMember.UserID) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, promotePendingMember.ACI) if err != nil { log.Err(err).Msg("failed getting expiring profile key credential for addMember") return nil, err @@ -1293,7 +1322,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, addRequestingMember := range decryptedGroupChange.AddRequestingMembers { - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addRequestingMember.UserID) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, addRequestingMember.ACI) if err != nil { log.Err(err).Msg("failed getting expiring profile key credential for addMember") return nil, err @@ -1313,7 +1342,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, deleteRequestingMember := range decryptedGroupChange.DeleteRequestingMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteRequestingMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(*deleteRequestingMember)) if err != nil { log.Err(err).Msg("Encrypt UserId error for promotePendingMember") return nil, err @@ -1323,7 +1352,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, promoteRequestingMember := range decryptedGroupChange.PromoteRequestingMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(promoteRequestingMember.UserID) + encryptedUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(promoteRequestingMember.ACI)) if err != nil { log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err @@ -1335,7 +1364,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, addBannedMember := range decryptedGroupChange.AddBannedMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(addBannedMember.UserID) + encryptedUserID, err := groupSecretParams.EncryptServiceID(addBannedMember.ServiceID) if err != nil { log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err @@ -1348,7 +1377,7 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup }) } for _, deleteBannedMember := range decryptedGroupChange.DeleteBannedMembers { - encryptedUserID, err := groupSecretParams.EncryptUUID(*deleteBannedMember) + encryptedUserID, err := groupSecretParams.EncryptServiceID(*deleteBannedMember) if err != nil { log.Err(err).Msg("Encrypt UserId error for promoteRequestingMember") return nil, err @@ -1399,12 +1428,18 @@ func (cli *Client) EncryptAndSignGroupChange(ctx context.Context, decryptedGroup return cli.patchGroup(ctx, groupChangeActions, groupMasterKey, nil) } -func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, error) { +func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.Member, *signalpb.PendingMember, error) { log := zerolog.Ctx(ctx) - expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, member.UserID) + expiringProfileKeyCredential, err := cli.FetchExpiringProfileKeyCredentialById(ctx, member.ACI) if err != nil { - log.Err(err).Msg("failed getting expiring profile key credential for addMember") - return nil, err + log.Err(err).Msg("failed getting expiring profile key credential for member, trying to encrypt as PendingMember") + pendingMember := PendingMember{ + ServiceID: member.UserServiceID(), + Role: member.Role, + AddedByUserID: cli.Store.ACI, + } + encryptedPendingMember, err := cli.encryptPendingMember(ctx, &pendingMember, groupSecretParams) + return nil, encryptedPendingMember, err } presentation, err := groupSecretParams.CreateExpiringProfileKeyCredentialPresentation( prodServerPublicParams, @@ -1412,13 +1447,35 @@ func (cli *Client) encryptMember(ctx context.Context, member *GroupMember, group ) if err != nil { log.Err(err).Msg("failed creating expiring profile key credential presentation for addMember") - return nil, err + return nil, nil, err } encryptedMember := signalpb.Member{ Presentation: *presentation, Role: signalpb.Member_Role(member.Role), } - return &encryptedMember, nil + return &encryptedMember, nil, nil +} + +func (cli *Client) encryptPendingMember(ctx context.Context, pendingMember *PendingMember, groupSecretParams *libsignalgo.GroupSecretParams) (*signalpb.PendingMember, error) { + log := zerolog.Ctx(ctx) + encryptedUserID, err := groupSecretParams.EncryptServiceID(pendingMember.ServiceID) + if err != nil { + log.Err(err).Msg("Encrypt UserId error for addPendingMember") + return nil, err + } + encryptedAddedByUserID, err := groupSecretParams.EncryptServiceID(libsignalgo.NewACIServiceID(pendingMember.AddedByUserID)) + if err != nil { + log.Err(err).Msg("Encrypt AddedByUserId error for addPendingMember") + return nil, err + } + encryptedPendingMember := signalpb.PendingMember{ + AddedByUserId: encryptedAddedByUserID[:], + Member: &signalpb.Member{ + UserId: encryptedUserID[:], + Role: signalpb.Member_Role(pendingMember.Role), + }, + } + return &encryptedPendingMember, nil } var ( @@ -1613,11 +1670,23 @@ func (cli *Client) EncryptGroup(ctx context.Context, decryptedGroup *Group, grou } } for _, member := range decryptedGroup.Members { - encryptedMember, err := cli.encryptMember(ctx, member, &groupSecretParams) + encryptedMember, encryptedPendingMember, err := cli.encryptMember(ctx, member, &groupSecretParams) if err != nil { log.Err(err).Msg("Failed to encrypt GroupMember") } - encryptedGroup.Members = append(encryptedGroup.Members, encryptedMember) + if encryptedMember != nil { + encryptedGroup.Members = append(encryptedGroup.Members, encryptedMember) + } else { + encryptedGroup.PendingMembers = append(encryptedGroup.PendingMembers, encryptedPendingMember) + } + } + for _, pendingMember := range decryptedGroup.PendingMembers { + encryptedPendingMember, err := cli.encryptPendingMember(ctx, pendingMember, &groupSecretParams) + if err != nil { + log.Err(err).Msg("Failed to encrypt pendingMember") + return nil, err + } + encryptedGroup.PendingMembers = append(encryptedGroup.PendingMembers, encryptedPendingMember) } return encryptedGroup, nil } diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index 473dd3e6..11211e00 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -544,16 +544,21 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte GroupV2: groupContext, } content := wrapDataMessageInContent(dm) - recipients := group.Members + var recipients []*libsignalgo.ServiceID + for _, member := range group.Members { + serviceID := member.UserServiceID() + recipients = append(recipients, &serviceID) + } for _, member := range group.PendingMembers { - recipients = append(recipients, &member.GroupMember) + recipients = append(recipients, &member.ServiceID) } if groupChange != nil { for _, member := range groupChange.AddPendingMembers { - recipients = append(recipients, &member.GroupMember) + recipients = append(recipients, &member.ServiceID) } for _, member := range groupChange.AddMembers { - recipients = append(recipients, &member.GroupMember) + serviceID := member.UserServiceID() + recipients = append(recipients, &serviceID) } } return cli.sendToGroup(ctx, recipients, content, timestamp) @@ -578,32 +583,37 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi messageTimestamp = content.EditMessage.DataMessage.GetTimestamp() content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) } - return cli.sendToGroup(ctx, group.Members, content, messageTimestamp) + var recipients []*libsignalgo.ServiceID + for _, member := range group.Members { + serviceID := member.UserServiceID() + recipients = append(recipients, &serviceID) + } + return cli.sendToGroup(ctx, recipients, content, messageTimestamp) } -func (cli *Client) sendToGroup(ctx context.Context, recipients []*GroupMember, content *signalpb.Content, messageTimestamp uint64) (*GroupMessageSendResult, error) { +func (cli *Client) sendToGroup(ctx context.Context, recipients []*libsignalgo.ServiceID, content *signalpb.Content, messageTimestamp uint64) (*GroupMessageSendResult, error) { // Send to each member of the group result := &GroupMessageSendResult{ SuccessfullySentTo: []SuccessfulSendResult{}, FailedToSendTo: []FailedSendResult{}, } - for _, member := range recipients { - if member.UserID == cli.Store.ACI { + for _, recipient := range recipients { + if recipient.Type == libsignalgo.ServiceIDTypeACI && recipient.UUID == cli.Store.ACI { // Don't send normal DataMessages to ourselves continue } - log := zerolog.Ctx(ctx).With().Stringer("member", member.UserID).Logger() + log := zerolog.Ctx(ctx).With().Stringer("member", *recipient).Logger() ctx := log.WithContext(ctx) - sentUnidentified, err := cli.sendContent(ctx, member.UserServiceID(), messageTimestamp, content, 0, true) + sentUnidentified, err := cli.sendContent(ctx, *recipient, messageTimestamp, content, 0, true) if err != nil { result.FailedToSendTo = append(result.FailedToSendTo, FailedSendResult{ - Recipient: member.UserServiceID(), + Recipient: *recipient, Error: err, }) log.Err(err).Msg("Failed to send to user") } else { result.SuccessfullySentTo = append(result.SuccessfullySentTo, SuccessfulSendResult{ - Recipient: member.UserServiceID(), + Recipient: *recipient, Unidentified: sentUnidentified, }) log.Trace().Msg("Successfully sent to user") diff --git a/portal.go b/portal.go index b5be7f37..0624b893 100644 --- a/portal.go +++ b/portal.go @@ -953,19 +953,19 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou intent := sender.IntentFor(portal) modifyRoles := groupChange.ModifyMemberRoles for _, deleteBannedMember := range groupChange.DeleteBannedMembers { - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deleteBannedMember, event.MembershipLeave, "unbanned") + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *&deleteBannedMember.UUID, event.MembershipLeave, "unbanned") if err != nil { log.Warn().Stringer("signal_user_id", deleteBannedMember).Msg("Couldn't get puppet for unban") } } for _, addMember := range groupChange.AddMembers { - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: addMember.UserID, Role: addMember.Role}) + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: addMember.ACI, Role: addMember.Role}) var puppet *Puppet if addMember.JoinFromInviteLink { - puppet = portal.bridge.GetPuppetBySignalID(addMember.UserID) + puppet = portal.bridge.GetPuppetBySignalID(addMember.ACI) if puppet != nil { if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(addMember.UserID) + user := portal.bridge.GetUserBySignalID(addMember.ACI) if user != nil { portal.MainIntent().SendCustomMembershipEvent(ctx, portal.MXID, user.MXID, event.MembershipInvite, "Joined via invite Link") } @@ -978,20 +978,23 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } } } else { - puppet, _ = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.UserID, event.MembershipInvite, "added") + puppet, _ = portal.sendMembershipForPuppetAndUser(ctx, sender, addMember.ACI, event.MembershipInvite, "added") } if puppet != nil { puppet.IntentFor(portal).SendCustomMembershipEvent(ctx, portal.MXID, puppet.IntentFor(portal).UserID, event.MembershipJoin, "") } else { - log.Warn().Stringer("signal_user_id", addMember.UserID).Msg("Couldn't get puppet for invite") + log.Warn().Stringer("signal_user_id", addMember.ACI).Msg("Couldn't get puppet for invite") } } bannedMembers := make(map[uuid.UUID]bool) for _, addBannedMember := range groupChange.AddBannedMembers { - bannedMembers[addBannedMember.UserID] = true - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addBannedMember.UserID, event.MembershipBan, "banned") + if addBannedMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + bannedMembers[addBannedMember.ServiceID.UUID] = true + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addBannedMember.ServiceID.UUID, event.MembershipBan, "banned") if err != nil { - log.Warn().Stringer("signal_user_id", addBannedMember.UserID).Msg("Couldn't get puppet for ban") + log.Warn().Stringer("signal_user_id", addBannedMember.ServiceID.UUID).Msg("Couldn't get puppet for ban") } } for _, deleteMember := range groupChange.DeleteMembers { @@ -1004,10 +1007,13 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } } for _, deletePendingMember := range groupChange.DeletePendingMembers { - if bannedMembers[*deletePendingMember] { + if deletePendingMember.Type == libsignalgo.ServiceIDTypePNI { continue } - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, *deletePendingMember, event.MembershipLeave, "invite withdrawn") + if bannedMembers[deletePendingMember.UUID] { + continue + } + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, deletePendingMember.UUID, event.MembershipLeave, "invite withdrawn") if err != nil { log.Warn().Stringer("signal_user_id", deletePendingMember).Msg("Couldn't get puppet for removal") } @@ -1022,35 +1028,46 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } } for _, promotePendingMember := range groupChange.PromotePendingMembers { - puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promotePendingMember.UserID, event.MembershipInvite, "request accepted") - if err == nil { - puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) - } else { - log.Warn().Stringer("signal_user_id", promotePendingMember.UserID).Msg("Couldn't get puppet for invite") + puppet := portal.bridge.GetPuppetBySignalID(promotePendingMember.ACI) + if puppet == nil { + log.Warn().Stringer("signal_user_id", promotePendingMember.ACI).Msg("Couldn't get puppet for invite") + continue + } + puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) + } + for _, promotePendingPniAciMember := range groupChange.PromotePendingPniAciMembers { + puppet := portal.bridge.GetPuppetBySignalID(promotePendingPniAciMember.ACI) + if puppet == nil { + log.Warn().Stringer("signal_user_id", promotePendingPniAciMember.ACI).Msg("Couldn't get puppet for invite") + continue } + puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) } for _, addPendingMember := range groupChange.AddPendingMembers { - _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addPendingMember.UserID, event.MembershipInvite, "invited") + if addPendingMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + _, err := portal.sendMembershipForPuppetAndUser(ctx, sender, addPendingMember.ServiceID.UUID, event.MembershipInvite, "invited") if err != nil { - log.Warn().Stringer("signal_user_id", addPendingMember.UserID).Msg("Couldn't get puppet for invite") + log.Warn().Stringer("signal_user_id", addPendingMember.ServiceID).Msg("Couldn't get puppet for invite") } - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: addPendingMember.UserID, Role: addPendingMember.Role}) + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: addPendingMember.ServiceID.UUID, Role: addPendingMember.Role}) } for _, promoteRequestingMember := range groupChange.PromoteRequestingMembers { - puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promoteRequestingMember.UserID, event.MembershipInvite, "accepted") + puppet, err := portal.sendMembershipForPuppetAndUser(ctx, sender, promoteRequestingMember.ACI, event.MembershipInvite, "accepted") if err == nil { err = puppet.IntentFor(portal).EnsureJoined(ctx, portal.MXID) if err != nil { - log.Warn().Stringer("signal_user_id", promoteRequestingMember.UserID).Msg("failed to join puppet") + log.Warn().Stringer("signal_user_id", promoteRequestingMember.ACI).Msg("failed to join puppet") } } else { - log.Warn().Stringer("signal_user_id", promoteRequestingMember.UserID).Msg("Couldn't get puppet for join") + log.Warn().Stringer("signal_user_id", promoteRequestingMember.ACI).Msg("Couldn't get puppet for join") } - modifyRoles = append(modifyRoles, &signalmeow.RoleMember{UserID: promoteRequestingMember.UserID, Role: promoteRequestingMember.Role}) + modifyRoles = append(modifyRoles, &signalmeow.RoleMember{ACI: promoteRequestingMember.ACI, Role: promoteRequestingMember.Role}) } for _, addRequestingMember := range groupChange.AddRequestingMembers { // sender and target should be the same SignalID - puppet := portal.bridge.GetPuppetBySignalID(addRequestingMember.UserID) + puppet := portal.bridge.GetPuppetBySignalID(addRequestingMember.ACI) if puppet != nil { portal.sendMembershipWithPuppet(ctx, sender, puppet.IntentFor(portal).UserID, event.MembershipKnock, "knocked") } @@ -1062,9 +1079,9 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou log.Err(err).Msg("Couldn't get power levels") } else { for _, modifyRole := range modifyRoles { - puppet := portal.bridge.GetPuppetBySignalID(modifyRole.UserID) + puppet := portal.bridge.GetPuppetBySignalID(modifyRole.ACI) if puppet == nil { - log.Warn().Stringer("signal_user_id", modifyRole.UserID).Msg("Couldn't get puppet for power level change") + log.Warn().Stringer("signal_user_id", modifyRole.ACI).Msg("Couldn't get puppet for power level change") continue } powerLevel := 0 @@ -1073,7 +1090,7 @@ func (portal *Portal) handleSignalGroupChange(source *User, sender *Puppet, grou } levels.EnsureUserLevel(puppet.IntentFor(portal).UserID, powerLevel) if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(modifyRole.UserID) + user := portal.bridge.GetUserBySignalID(modifyRole.ACI) if user != nil { levels.EnsureUserLevel(user.MXID, powerLevel) } @@ -2237,14 +2254,14 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } } for _, member := range info.Members { - puppet := portal.bridge.GetPuppetBySignalID(member.UserID) + puppet := portal.bridge.GetPuppetBySignalID(member.ACI) if puppet == nil { - log.Warn().Stringer("signal_user_id", member.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", member.ACI).Msg("Couldn't get puppet for group member") continue } puppet.UpdateInfo(ctx, source) intent := puppet.IntentFor(portal) - if member.UserID != source.SignalID && portal.MXID != "" { + if member.ACI != source.SignalID && portal.MXID != "" { userIDs[intent.UserID] = ((int)(member.Role) >> 1) * 50 } delete(currentMembers, intent.UserID) @@ -2252,11 +2269,11 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * if currentMembers[intent.UserID] != event.MembershipJoin { err := intent.EnsureJoined(ctx, portal.MXID) if err != nil { - log.Err(err).Stringer("signal_user_id", member.UserID).Msg("Failed to ensure user is joined to portal") + log.Err(err).Stringer("signal_user_id", member.ACI).Msg("Failed to ensure user is joined to portal") } } if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(member.UserID) + user := portal.bridge.GetUserBySignalID(member.ACI) if user != nil { delete(currentMembers, user.MXID) userIDs[user.MXID] = ((int)(member.Role) >> 1) * 50 @@ -2273,9 +2290,12 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * return userIDs } for _, pendingMember := range info.PendingMembers { - puppet := portal.bridge.GetPuppetBySignalID(pendingMember.UserID) + if pendingMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + puppet := portal.bridge.GetPuppetBySignalID(pendingMember.ServiceID.UUID) if puppet == nil { - log.Warn().Stringer("signal_user_id", pendingMember.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", pendingMember.ServiceID.UUID).Msg("Couldn't get puppet for group member") continue } mxid := puppet.IntentFor(portal).UserID @@ -2295,7 +2315,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * userIDs[mxid] = ((int)(pendingMember.Role) >> 1) * 50 delete(currentMembers, mxid) if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(pendingMember.UserID) + user := portal.bridge.GetUserBySignalID(pendingMember.ServiceID.UUID) if user == nil { continue } @@ -2319,9 +2339,9 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } } for _, requestingMember := range info.RequestingMembers { - puppet := portal.bridge.GetPuppetBySignalID(requestingMember.UserID) + puppet := portal.bridge.GetPuppetBySignalID(requestingMember.ACI) if puppet == nil { - log.Warn().Stringer("signal_user_id", requestingMember.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", requestingMember.ACI).Msg("Couldn't get puppet for group member") continue } mxid := puppet.IntentFor(portal).UserID @@ -2341,9 +2361,12 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * delete(currentMembers, mxid) } for _, bannedMember := range info.BannedMembers { - puppet := portal.bridge.GetPuppetBySignalID(bannedMember.UserID) + if bannedMember.ServiceID.Type == libsignalgo.ServiceIDTypePNI { + continue + } + puppet := portal.bridge.GetPuppetBySignalID(bannedMember.ServiceID.UUID) if puppet == nil { - log.Warn().Stringer("signal_user_id", bannedMember.UserID).Msg("Couldn't get puppet for group member") + log.Warn().Stringer("signal_user_id", bannedMember.ServiceID.UUID).Msg("Couldn't get puppet for group member") continue } mxid := puppet.IntentFor(portal).UserID @@ -2355,7 +2378,7 @@ func (portal *Portal) SyncParticipants(ctx context.Context, source *User, info * } delete(currentMembers, mxid) if puppet.customIntent == nil { - user := portal.bridge.GetUserBySignalID(bannedMember.UserID) + user := portal.bridge.GetUserBySignalID(bannedMember.ServiceID.UUID) if user == nil { continue } @@ -2590,8 +2613,8 @@ func (portal *Portal) HandleMatrixInvite(brSender bridge.User, brGhost bridge.Gh } groupChange := &signalmeow.GroupChange{AddMembers: []*signalmeow.AddMember{{ GroupMember: signalmeow.GroupMember{ - UserID: puppet.SignalID, - Role: role, + ACI: puppet.SignalID, + Role: role, }, }}} revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) @@ -2621,8 +2644,8 @@ func (portal *Portal) HandleMatrixAcceptKnock(brSender bridge.User, brGhost brid } } groupChange := &signalmeow.GroupChange{PromoteRequestingMembers: []*signalmeow.RoleMember{{ - UserID: puppet.SignalID, - Role: role, + ACI: puppet.SignalID, + Role: role, }}} revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { @@ -2675,7 +2698,7 @@ func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost sender := brSender.(*User) puppet := brGhost.(*Puppet) groupChange := &signalmeow.GroupChange{AddBannedMembers: []*signalmeow.BannedMember{{ - UserID: puppet.SignalID, + ServiceID: libsignalgo.NewACIServiceID(puppet.SignalID), Timestamp: uint64(time.Now().UnixMilli()), }}} switch prevMembership := evt.Unsigned.PrevContent.AsMember().Membership; prevMembership { @@ -2684,7 +2707,8 @@ func (portal *Portal) HandleMatrixBan(brSender bridge.User, brGhost bridge.Ghost case event.MembershipKnock: groupChange.DeleteRequestingMembers = []*uuid.UUID{&puppet.SignalID} case event.MembershipInvite: - groupChange.DeletePendingMembers = []*uuid.UUID{&puppet.SignalID} + serviceID := libsignalgo.NewACIServiceID(puppet.SignalID) + groupChange.DeletePendingMembers = []*libsignalgo.ServiceID{&serviceID} } revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { @@ -2703,7 +2727,8 @@ func (portal *Portal) HandleMatrixUnban(brSender bridge.User, brGhost bridge.Gho ctx := log.WithContext(context.TODO()) sender := brSender.(*User) puppet := brGhost.(*Puppet) - groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*uuid.UUID{&puppet.SignalID}} + serviceID := libsignalgo.NewACIServiceID(puppet.SignalID) + groupChange := &signalmeow.GroupChange{DeleteBannedMembers: []*libsignalgo.ServiceID{&serviceID}} revision, err := sender.Client.UpdateGroup(ctx, groupChange, portal.GroupID()) if err != nil { log.Err(err).Msg("Error unbanning on Signal") @@ -2748,8 +2773,8 @@ func (portal *Portal) HandleMatrixPowerLevels(brSender bridge.User, evt *event.E role = signalmeow.GroupMember_ADMINISTRATOR } groupChange.ModifyMemberRoles = append(groupChange.ModifyMemberRoles, &signalmeow.RoleMember{ - UserID: puppet.SignalID, - Role: role, + ACI: puppet.SignalID, + Role: role, }) } }