mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
Update libsignal-service
This commit is contained in:
parent
73b4239744
commit
f1d735f93d
22 changed files with 229 additions and 555 deletions
|
@ -8,7 +8,7 @@ import org.signal.libsignal.protocol.message.CiphertextMessage;
|
|||
import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.Envelope;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -62,10 +62,14 @@ public class SendRetryMessageRequestAction implements HandleAction {
|
|||
}
|
||||
|
||||
private static int envelopeTypeToCiphertextMessageType(int envelopeType) {
|
||||
return switch (envelopeType) {
|
||||
case SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE -> CiphertextMessage.PREKEY_TYPE;
|
||||
case SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER_VALUE -> CiphertextMessage.SENDERKEY_TYPE;
|
||||
case SignalServiceProtos.Envelope.Type.PLAINTEXT_CONTENT_VALUE -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE;
|
||||
final var type = Envelope.Type.fromValue(envelopeType);
|
||||
if (type == null) {
|
||||
return CiphertextMessage.WHISPER_TYPE;
|
||||
}
|
||||
return switch (type) {
|
||||
case PREKEY_BUNDLE -> CiphertextMessage.PREKEY_TYPE;
|
||||
case UNIDENTIFIED_SENDER -> CiphertextMessage.SENDERKEY_TYPE;
|
||||
case PLAINTEXT_CONTENT -> CiphertextMessage.PLAINTEXT_CONTENT_TYPE;
|
||||
default -> CiphertextMessage.WHISPER_TYPE;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.asamk.signal.manager.api;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.asamk.signal.manager.groups.GroupLinkPassword;
|
||||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
||||
|
@ -13,6 +11,8 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public final class GroupInviteLinkUrl {
|
||||
|
||||
private static final String GROUP_URL_HOST = "signal.group";
|
||||
|
@ -24,7 +24,7 @@ public final class GroupInviteLinkUrl {
|
|||
|
||||
public static GroupInviteLinkUrl forGroup(GroupMasterKey groupMasterKey, DecryptedGroup group) {
|
||||
return new GroupInviteLinkUrl(groupMasterKey,
|
||||
GroupLinkPassword.fromBytes(group.getInviteLinkPassword().toByteArray()));
|
||||
GroupLinkPassword.fromBytes(group.inviteLinkPassword.toByteArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,19 +50,16 @@ public final class GroupInviteLinkUrl {
|
|||
}
|
||||
|
||||
var bytes = Base64UrlSafe.decodePaddingAgnostic(encoding);
|
||||
var groupInviteLink = GroupInviteLink.parseFrom(bytes);
|
||||
GroupInviteLink groupInviteLink = GroupInviteLink.ADAPTER.decode(bytes);
|
||||
|
||||
switch (groupInviteLink.getContentsCase()) {
|
||||
case V1CONTENTS -> {
|
||||
var groupInviteLinkContentsV1 = groupInviteLink.getV1Contents();
|
||||
var groupMasterKey = new GroupMasterKey(groupInviteLinkContentsV1.getGroupMasterKey()
|
||||
.toByteArray());
|
||||
var password = GroupLinkPassword.fromBytes(groupInviteLinkContentsV1.getInviteLinkPassword()
|
||||
.toByteArray());
|
||||
if (groupInviteLink.v1Contents != null) {
|
||||
var groupInviteLinkContentsV1 = groupInviteLink.v1Contents;
|
||||
var groupMasterKey = new GroupMasterKey(groupInviteLinkContentsV1.groupMasterKey.toByteArray());
|
||||
var password = GroupLinkPassword.fromBytes(groupInviteLinkContentsV1.inviteLinkPassword.toByteArray());
|
||||
|
||||
return new GroupInviteLinkUrl(groupMasterKey, password);
|
||||
}
|
||||
default -> throw new UnknownGroupLinkVersionException("Url contains no known group link content");
|
||||
return new GroupInviteLinkUrl(groupMasterKey, password);
|
||||
} else {
|
||||
throw new UnknownGroupLinkVersionException("Url contains no known group link content");
|
||||
}
|
||||
} catch (InvalidInputException | IOException e) {
|
||||
throw new InvalidGroupLinkException(e);
|
||||
|
@ -93,13 +90,12 @@ public final class GroupInviteLinkUrl {
|
|||
}
|
||||
|
||||
private static String createUrl(GroupMasterKey groupMasterKey, GroupLinkPassword password) {
|
||||
var groupInviteLink = GroupInviteLink.newBuilder()
|
||||
.setV1Contents(GroupInviteLink.GroupInviteLinkContentsV1.newBuilder()
|
||||
.setGroupMasterKey(ByteString.copyFrom(groupMasterKey.serialize()))
|
||||
.setInviteLinkPassword(ByteString.copyFrom(password.serialize())))
|
||||
.build();
|
||||
var groupInviteLink = new GroupInviteLink.Builder().v1Contents(new GroupInviteLink.GroupInviteLinkContentsV1.Builder().groupMasterKey(
|
||||
ByteString.of(groupMasterKey.serialize()))
|
||||
.inviteLinkPassword(ByteString.of(password.serialize()))
|
||||
.build()).build();
|
||||
|
||||
var encoding = Base64UrlSafe.encodeBytesWithoutPadding(groupInviteLink.toByteArray());
|
||||
var encoding = Base64UrlSafe.encodeBytesWithoutPadding(groupInviteLink.encode());
|
||||
|
||||
return GROUP_URL_PREFIX + encoding;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,6 @@ import java.util.Optional;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.BodyRange;
|
||||
|
||||
public record MessageEnvelope(
|
||||
Optional<RecipientAddress> sourceAddress,
|
||||
int sourceDevice,
|
||||
|
@ -160,7 +158,7 @@ public record MessageEnvelope(
|
|||
.map(a -> a.stream().map(preview -> Preview.from(preview, fileProvider)).toList())
|
||||
.orElse(List.of()),
|
||||
dataMessage.getBodyRanges()
|
||||
.map(a -> a.stream().filter(BodyRange::hasStyle).map(TextStyle::from).toList())
|
||||
.map(a -> a.stream().filter(r -> r.style != null).map(TextStyle::from).toList())
|
||||
.orElse(List.of()));
|
||||
}
|
||||
|
||||
|
@ -250,7 +248,7 @@ public record MessageEnvelope(
|
|||
? List.of()
|
||||
: quote.getBodyRanges()
|
||||
.stream()
|
||||
.filter(BodyRange::hasStyle)
|
||||
.filter(r -> r.style != null)
|
||||
.map(TextStyle::from)
|
||||
.toList());
|
||||
}
|
||||
|
@ -765,13 +763,12 @@ public record MessageEnvelope(
|
|||
}
|
||||
}
|
||||
|
||||
public record Hangup(long id, Type type, int deviceId, boolean isLegacy) {
|
||||
public record Hangup(long id, Type type, int deviceId) {
|
||||
|
||||
static Hangup from(HangupMessage hangupMessage) {
|
||||
return new Hangup(hangupMessage.getId(),
|
||||
Type.from(hangupMessage.getType()),
|
||||
hangupMessage.getDeviceId(),
|
||||
hangupMessage.isLegacy());
|
||||
hangupMessage.getDeviceId());
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.asamk.signal.manager.api;
|
||||
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.BodyRange;
|
||||
|
||||
public record TextStyle(Style style, int start, int length) {
|
||||
public record TextStyle(Style style, Integer start, Integer length) {
|
||||
|
||||
public enum Style {
|
||||
NONE,
|
||||
|
@ -12,7 +12,10 @@ public record TextStyle(Style style, int start, int length) {
|
|||
STRIKETHROUGH,
|
||||
MONOSPACE;
|
||||
|
||||
static Style fromInternal(SignalServiceProtos.BodyRange.Style style) {
|
||||
static Style fromInternal(BodyRange.Style style) {
|
||||
if (style == null) {
|
||||
return NONE;
|
||||
}
|
||||
return switch (style) {
|
||||
case NONE -> NONE;
|
||||
case BOLD -> BOLD;
|
||||
|
@ -35,27 +38,26 @@ public record TextStyle(Style style, int start, int length) {
|
|||
};
|
||||
}
|
||||
|
||||
SignalServiceProtos.BodyRange.Style toBodyRangeStyle() {
|
||||
BodyRange.Style toBodyRangeStyle() {
|
||||
return switch (this) {
|
||||
case NONE -> SignalServiceProtos.BodyRange.Style.NONE;
|
||||
case BOLD -> SignalServiceProtos.BodyRange.Style.BOLD;
|
||||
case ITALIC -> SignalServiceProtos.BodyRange.Style.ITALIC;
|
||||
case SPOILER -> SignalServiceProtos.BodyRange.Style.SPOILER;
|
||||
case STRIKETHROUGH -> SignalServiceProtos.BodyRange.Style.STRIKETHROUGH;
|
||||
case MONOSPACE -> SignalServiceProtos.BodyRange.Style.MONOSPACE;
|
||||
case NONE -> BodyRange.Style.NONE;
|
||||
case BOLD -> BodyRange.Style.BOLD;
|
||||
case ITALIC -> BodyRange.Style.ITALIC;
|
||||
case SPOILER -> BodyRange.Style.SPOILER;
|
||||
case STRIKETHROUGH -> BodyRange.Style.STRIKETHROUGH;
|
||||
case MONOSPACE -> BodyRange.Style.MONOSPACE;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static TextStyle from(SignalServiceProtos.BodyRange bodyRange) {
|
||||
return new TextStyle(Style.fromInternal(bodyRange.getStyle()), bodyRange.getStart(), bodyRange.getLength());
|
||||
static TextStyle from(BodyRange bodyRange) {
|
||||
return new TextStyle(Style.fromInternal(bodyRange.style), bodyRange.start, bodyRange.length);
|
||||
}
|
||||
|
||||
public SignalServiceProtos.BodyRange toBodyRange() {
|
||||
return SignalServiceProtos.BodyRange.newBuilder()
|
||||
.setStart(this.start())
|
||||
.setLength(this.length())
|
||||
.setStyle(this.style().toBodyRangeStyle())
|
||||
public BodyRange toBodyRange() {
|
||||
return new BodyRange.Builder().start(this.start())
|
||||
.length(this.length())
|
||||
.style(this.style().toBodyRangeStyle())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class GroupUtils {
|
|||
} else {
|
||||
final var groupInfoV2 = (GroupInfoV2) groupInfo;
|
||||
var group = SignalServiceGroupV2.newBuilder(groupInfoV2.getMasterKey())
|
||||
.withRevision(groupInfoV2.getGroup() == null ? 0 : groupInfoV2.getGroup().getRevision())
|
||||
.withRevision(groupInfoV2.getGroup() == null ? 0 : groupInfoV2.getGroup().revision)
|
||||
.build();
|
||||
messageBuilder.asGroupMessage(group);
|
||||
}
|
||||
|
|
|
@ -125,11 +125,11 @@ public class GroupHelper {
|
|||
groupInfoV2 = new GroupInfoV2(groupId, groupMasterKey, account.getRecipientResolver());
|
||||
}
|
||||
|
||||
if (groupInfoV2.getGroup() == null || groupInfoV2.getGroup().getRevision() < revision) {
|
||||
if (groupInfoV2.getGroup() == null || groupInfoV2.getGroup().revision < revision) {
|
||||
DecryptedGroup group = null;
|
||||
if (signedGroupChange != null
|
||||
&& groupInfoV2.getGroup() != null
|
||||
&& groupInfoV2.getGroup().getRevision() + 1 == revision) {
|
||||
&& groupInfoV2.getGroup().revision + 1 == revision) {
|
||||
final var decryptedGroupChange = context.getGroupV2Helper()
|
||||
.getDecryptedGroupChange(signedGroupChange, groupMasterKey);
|
||||
|
||||
|
@ -151,8 +151,8 @@ public class GroupHelper {
|
|||
}
|
||||
if (group != null) {
|
||||
storeProfileKeysFromMembers(group);
|
||||
final var avatar = group.getAvatar();
|
||||
if (avatar != null && !avatar.isEmpty()) {
|
||||
final var avatar = group.avatar;
|
||||
if (!avatar.isEmpty()) {
|
||||
downloadGroupAvatar(groupId, groupSecretParams, avatar);
|
||||
}
|
||||
}
|
||||
|
@ -300,14 +300,14 @@ public class GroupHelper {
|
|||
} catch (GroupLinkNotActiveException e) {
|
||||
throw new InactiveGroupLinkException("Group link inactive (reason: " + e.getReason() + ")", e);
|
||||
}
|
||||
if (groupJoinInfo.getPendingAdminApproval()) {
|
||||
if (groupJoinInfo.pendingAdminApproval) {
|
||||
throw new PendingAdminApprovalException("You have already requested to join the group.");
|
||||
}
|
||||
final var groupChange = context.getGroupV2Helper()
|
||||
.joinGroup(inviteLinkUrl.getGroupMasterKey(), inviteLinkUrl.getPassword(), groupJoinInfo);
|
||||
final var group = getOrMigrateGroup(inviteLinkUrl.getGroupMasterKey(),
|
||||
groupJoinInfo.getRevision() + 1,
|
||||
groupChange.toByteArray());
|
||||
groupJoinInfo.revision + 1,
|
||||
groupChange.encode());
|
||||
|
||||
if (group.getGroup() == null) {
|
||||
// Only requested member, can't send update to group members
|
||||
|
@ -400,8 +400,8 @@ public class GroupHelper {
|
|||
} catch (NotAGroupMemberException ignored) {
|
||||
}
|
||||
storeProfileKeysFromMembers(decryptedGroup);
|
||||
final var avatar = decryptedGroup.getAvatar();
|
||||
if (avatar != null && !avatar.isEmpty()) {
|
||||
final var avatar = decryptedGroup.avatar;
|
||||
if (!avatar.isEmpty()) {
|
||||
downloadGroupAvatar(groupInfoV2.getGroupId(), groupSecretParams, avatar);
|
||||
}
|
||||
}
|
||||
|
@ -446,8 +446,8 @@ public class GroupHelper {
|
|||
}
|
||||
|
||||
private void storeProfileKeysFromMembers(final DecryptedGroup group) {
|
||||
for (var member : group.getMembersList()) {
|
||||
final var serviceId = ServiceId.parseOrThrow(member.getAciBytes());
|
||||
for (var member : group.members) {
|
||||
final var serviceId = ServiceId.parseOrThrow(member.aciBytes);
|
||||
final var recipientId = account.getRecipientResolver().resolveRecipient(serviceId);
|
||||
final var profileStore = account.getProfileStore();
|
||||
if (profileStore.getProfileKey(recipientId) != null) {
|
||||
|
@ -455,7 +455,7 @@ public class GroupHelper {
|
|||
continue;
|
||||
}
|
||||
try {
|
||||
profileStore.storeProfileKey(recipientId, new ProfileKey(member.getProfileKey().toByteArray()));
|
||||
profileStore.storeProfileKey(recipientId, new ProfileKey(member.profileKey.toByteArray()));
|
||||
} catch (InvalidInputException ignored) {
|
||||
}
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ public class GroupHelper {
|
|||
final DecryptedGroup newDecryptedGroup
|
||||
) throws NotAGroupMemberException {
|
||||
final var revisionWeWereAdded = context.getGroupV2Helper().findRevisionWeWereAdded(newDecryptedGroup);
|
||||
final var localRevision = localGroup.getGroup() == null ? 0 : localGroup.getGroup().getRevision();
|
||||
final var localRevision = localGroup.getGroup() == null ? 0 : localGroup.getGroup().revision;
|
||||
var fromRevision = Math.max(revisionWeWereAdded, localRevision);
|
||||
final var newProfileKeys = new HashMap<RecipientId, ProfileKey>();
|
||||
while (true) {
|
||||
|
@ -753,7 +753,7 @@ public class GroupHelper {
|
|||
groupInfoV2.setGroup(groupGroupChangePair.first());
|
||||
account.getGroupStore().updateGroup(groupInfoV2);
|
||||
|
||||
var messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupGroupChangePair.second().toByteArray());
|
||||
var messageBuilder = getGroupUpdateMessageBuilder(groupInfoV2, groupGroupChangePair.second().encode());
|
||||
return sendGroupMessage(messageBuilder,
|
||||
groupInfoV2.getMembersIncludingPendingWithout(account.getSelfRecipientId()),
|
||||
groupInfoV2.getDistributionId());
|
||||
|
@ -782,7 +782,7 @@ public class GroupHelper {
|
|||
|
||||
private SignalServiceDataMessage.Builder getGroupUpdateMessageBuilder(GroupInfoV2 g, byte[] signedGroupChange) {
|
||||
var group = SignalServiceGroupV2.newBuilder(g.getMasterKey())
|
||||
.withRevision(g.getGroup().getRevision())
|
||||
.withRevision(g.getGroup().revision)
|
||||
.withSignedGroupChange(signedGroupChange);
|
||||
return SignalServiceDataMessage.newBuilder()
|
||||
.asGroupMessage(group.build())
|
||||
|
@ -798,7 +798,7 @@ public class GroupHelper {
|
|||
members.addAll(group.getMembersIncludingPendingWithout(selfRecipientId));
|
||||
account.getGroupStore().updateGroup(group);
|
||||
|
||||
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.toByteArray());
|
||||
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.encode());
|
||||
return sendGroupMessage(messageBuilder, members, group.getDistributionId());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package org.asamk.signal.manager.helper;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.asamk.signal.manager.api.GroupLinkState;
|
||||
import org.asamk.signal.manager.api.GroupPermission;
|
||||
import org.asamk.signal.manager.api.NotAGroupMemberException;
|
||||
|
@ -28,7 +25,6 @@ import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
|
|||
import org.signal.storageservice.protos.groups.local.DecryptedGroupJoinInfo;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||
|
@ -59,6 +55,8 @@ import java.util.function.Function;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
class GroupV2Helper {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(GroupV2Helper.class);
|
||||
|
@ -126,12 +124,12 @@ class GroupV2Helper {
|
|||
int findRevisionWeWereAdded(DecryptedGroup partialDecryptedGroup) {
|
||||
ByteString aciBytes = getSelfAci().toByteString();
|
||||
ByteString pniBytes = getSelfPni().toByteString();
|
||||
for (DecryptedMember decryptedMember : partialDecryptedGroup.getMembersList()) {
|
||||
if (decryptedMember.getAciBytes().equals(aciBytes) || decryptedMember.getPniBytes().equals(pniBytes)) {
|
||||
return decryptedMember.getJoinedAtRevision();
|
||||
for (DecryptedMember decryptedMember : partialDecryptedGroup.members) {
|
||||
if (decryptedMember.aciBytes.equals(aciBytes) || decryptedMember.pniBytes.equals(pniBytes)) {
|
||||
return decryptedMember.joinedAtRevision;
|
||||
}
|
||||
}
|
||||
return partialDecryptedGroup.getRevision();
|
||||
return partialDecryptedGroup.revision;
|
||||
}
|
||||
|
||||
Pair<GroupInfoV2, DecryptedGroup> createGroup(
|
||||
|
@ -203,19 +201,19 @@ class GroupV2Helper {
|
|||
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
|
||||
var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
|
||||
|
||||
var change = name != null ? groupOperations.createModifyGroupTitle(name) : GroupChange.Actions.newBuilder();
|
||||
var change = name != null ? groupOperations.createModifyGroupTitle(name) : new GroupChange.Actions.Builder();
|
||||
|
||||
if (description != null) {
|
||||
change.setModifyDescription(groupOperations.createModifyGroupDescriptionAction(description));
|
||||
change.modifyDescription(groupOperations.createModifyGroupDescriptionAction(description).build());
|
||||
}
|
||||
|
||||
if (avatarFile != null) {
|
||||
var avatarCdnKey = dependencies.getGroupsV2Api()
|
||||
.uploadAvatar(avatarFile, groupSecretParams, getGroupAuthForToday(groupSecretParams));
|
||||
change.setModifyAvatar(GroupChange.Actions.ModifyAvatarAction.newBuilder().setAvatar(avatarCdnKey));
|
||||
change.modifyAvatar(new GroupChange.Actions.ModifyAvatarAction.Builder().avatar(avatarCdnKey).build());
|
||||
}
|
||||
|
||||
change.setSourceServiceId(getSelfAci().toByteString());
|
||||
change.sourceServiceId(getSelfAci().toByteString());
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -241,7 +239,7 @@ class GroupV2Helper {
|
|||
final var aci = getSelfAci();
|
||||
final var change = groupOperations.createModifyGroupMembershipChange(candidates, bannedUuids, aci);
|
||||
|
||||
change.setSourceServiceId(getSelfAci().toByteString());
|
||||
change.sourceServiceId(getSelfAci().toByteString());
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -249,7 +247,7 @@ class GroupV2Helper {
|
|||
Pair<DecryptedGroup, GroupChange> leaveGroup(
|
||||
GroupInfoV2 groupInfoV2, Set<RecipientId> membersToMakeAdmin
|
||||
) throws IOException {
|
||||
var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
|
||||
var pendingMembersList = groupInfoV2.getGroup().pendingMembers;
|
||||
final var selfAci = getSelfAci();
|
||||
var selfPendingMember = DecryptedGroupUtil.findPendingByServiceId(pendingMembersList, selfAci);
|
||||
|
||||
|
@ -302,7 +300,7 @@ class GroupV2Helper {
|
|||
Pair<DecryptedGroup, GroupChange> revokeInvitedMembers(
|
||||
GroupInfoV2 groupInfoV2, Set<RecipientId> members
|
||||
) throws IOException {
|
||||
var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
|
||||
var pendingMembersList = groupInfoV2.getGroup().pendingMembers;
|
||||
final var memberUuids = members.stream()
|
||||
.map(context.getRecipientHelper()::resolveSignalServiceAddress)
|
||||
.map(SignalServiceAddress::getServiceId)
|
||||
|
@ -324,9 +322,9 @@ class GroupV2Helper {
|
|||
|
||||
final var change = groupOperations.createBanServiceIdsChange(serviceIds,
|
||||
false,
|
||||
groupInfoV2.getGroup().getBannedMembersList());
|
||||
groupInfoV2.getGroup().bannedMembers);
|
||||
|
||||
change.setSourceServiceId(getSelfAci().toByteString());
|
||||
change.sourceServiceId(getSelfAci().toByteString());
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -342,7 +340,7 @@ class GroupV2Helper {
|
|||
|
||||
final var change = groupOperations.createUnbanServiceIdsChange(serviceIds);
|
||||
|
||||
change.setSourceServiceId(getSelfAci().toByteString());
|
||||
change.sourceServiceId(getSelfAci().toByteString());
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -360,9 +358,8 @@ class GroupV2Helper {
|
|||
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
|
||||
|
||||
final var accessRequired = toAccessControl(state);
|
||||
final var requiresNewPassword = state != GroupLinkState.DISABLED && groupInfoV2.getGroup()
|
||||
.getInviteLinkPassword()
|
||||
.isEmpty();
|
||||
final var requiresNewPassword = state != GroupLinkState.DISABLED
|
||||
&& groupInfoV2.getGroup().inviteLinkPassword.toByteArray().length == 0;
|
||||
|
||||
final var change = requiresNewPassword ? groupOperations.createModifyGroupLinkPasswordAndRightsChange(
|
||||
GroupLinkPassword.createNew().serialize(),
|
||||
|
@ -393,14 +390,14 @@ class GroupV2Helper {
|
|||
Pair<DecryptedGroup, GroupChange> updateSelfProfileKey(GroupInfoV2 groupInfoV2) throws IOException {
|
||||
Optional<DecryptedMember> selfInGroup = groupInfoV2.getGroup() == null
|
||||
? Optional.empty()
|
||||
: DecryptedGroupUtil.findMemberByAci(groupInfoV2.getGroup().getMembersList(), getSelfAci());
|
||||
: DecryptedGroupUtil.findMemberByAci(groupInfoV2.getGroup().members, getSelfAci());
|
||||
if (selfInGroup.isEmpty()) {
|
||||
logger.trace("Not updating group, self not in group " + groupInfoV2.getGroupId().toBase64());
|
||||
return null;
|
||||
}
|
||||
|
||||
final var profileKey = context.getAccount().getProfileKey();
|
||||
if (Arrays.equals(profileKey.serialize(), selfInGroup.get().getProfileKey().toByteArray())) {
|
||||
if (Arrays.equals(profileKey.serialize(), selfInGroup.get().profileKey.toByteArray())) {
|
||||
logger.trace("Not updating group, own Profile Key is already up to date in group "
|
||||
+ groupInfoV2.getGroupId().toBase64());
|
||||
return null;
|
||||
|
@ -416,7 +413,7 @@ class GroupV2Helper {
|
|||
|
||||
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
|
||||
final var change = groupOperations.createUpdateProfileKeyCredentialChange(profileKeyCredential);
|
||||
change.setSourceServiceId(getSelfAci().toByteString());
|
||||
change.sourceServiceId(getSelfAci().toByteString());
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
||||
|
@ -434,17 +431,17 @@ class GroupV2Helper {
|
|||
throw new IOException("Cannot join a V2 group as self does not have a versioned profile");
|
||||
}
|
||||
|
||||
var requestToJoin = decryptedGroupJoinInfo.getAddFromInviteLink() == AccessControl.AccessRequired.ADMINISTRATOR;
|
||||
var requestToJoin = decryptedGroupJoinInfo.addFromInviteLink == AccessControl.AccessRequired.ADMINISTRATOR;
|
||||
var change = requestToJoin
|
||||
? groupOperations.createGroupJoinRequest(profileKeyCredential)
|
||||
: groupOperations.createGroupJoinDirect(profileKeyCredential);
|
||||
|
||||
change.setSourceServiceId(context.getRecipientHelper()
|
||||
change.sourceServiceId(context.getRecipientHelper()
|
||||
.resolveSignalServiceAddress(selfRecipientId)
|
||||
.getServiceId()
|
||||
.toByteString());
|
||||
|
||||
return commitChange(groupSecretParams, decryptedGroupJoinInfo.getRevision(), change, groupLinkPassword);
|
||||
return commitChange(groupSecretParams, decryptedGroupJoinInfo.revision, change, groupLinkPassword);
|
||||
}
|
||||
|
||||
Pair<DecryptedGroup, GroupChange> acceptInvite(GroupInfoV2 groupInfoV2) throws IOException {
|
||||
|
@ -459,7 +456,7 @@ class GroupV2Helper {
|
|||
final var change = groupOperations.createAcceptInviteChange(profileKeyCredential);
|
||||
|
||||
final var aci = context.getRecipientHelper().resolveSignalServiceAddress(selfRecipientId).getServiceId();
|
||||
change.setSourceServiceId(aci.toByteString());
|
||||
change.sourceServiceId(aci.toByteString());
|
||||
|
||||
return commitChange(groupInfoV2, change);
|
||||
}
|
||||
|
@ -520,7 +517,7 @@ class GroupV2Helper {
|
|||
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
|
||||
final var uuidCipherTexts = pendingMembers.stream().map(member -> {
|
||||
try {
|
||||
return new UuidCiphertext(member.getServiceIdCipherText().toByteArray());
|
||||
return new UuidCiphertext(member.serviceIdCipherText.toByteArray());
|
||||
} catch (InvalidInputException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
@ -555,8 +552,8 @@ class GroupV2Helper {
|
|||
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
|
||||
final var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
|
||||
final var previousGroupState = groupInfoV2.getGroup();
|
||||
final var nextRevision = previousGroupState.getRevision() + 1;
|
||||
final var changeActions = change.setRevision(nextRevision).build();
|
||||
final var nextRevision = previousGroupState.revision + 1;
|
||||
final var changeActions = change.revision(nextRevision).build();
|
||||
final DecryptedGroupChange decryptedChange;
|
||||
final DecryptedGroup decryptedGroupState;
|
||||
|
||||
|
@ -580,7 +577,7 @@ class GroupV2Helper {
|
|||
GroupLinkPassword password
|
||||
) throws IOException {
|
||||
final var nextRevision = currentRevision + 1;
|
||||
final var changeActions = change.setRevision(nextRevision).build();
|
||||
final var changeActions = change.revision(nextRevision).build();
|
||||
|
||||
return dependencies.getGroupsV2Api()
|
||||
.patchGroup(changeActions,
|
||||
|
@ -589,17 +586,16 @@ class GroupV2Helper {
|
|||
}
|
||||
|
||||
Pair<ServiceId, ProfileKey> getAuthoritativeProfileKeyFromChange(final DecryptedGroupChange change) {
|
||||
UUID editor = UuidUtil.fromByteStringOrNull(change.getEditorServiceIdBytes());
|
||||
final var editorProfileKeyBytes = Stream.concat(Stream.of(change.getNewMembersList().stream(),
|
||||
change.getPromotePendingMembersList().stream(),
|
||||
change.getModifiedProfileKeysList().stream())
|
||||
UUID editor = UuidUtil.fromByteStringOrNull(change.editorServiceIdBytes);
|
||||
final var editorProfileKeyBytes = Stream.concat(Stream.of(change.newMembers.stream(),
|
||||
change.promotePendingMembers.stream(),
|
||||
change.modifiedProfileKeys.stream())
|
||||
.flatMap(Function.identity())
|
||||
.filter(m -> UuidUtil.fromByteString(m.getAciBytes()).equals(editor))
|
||||
.map(DecryptedMember::getProfileKey),
|
||||
change.getNewRequestingMembersList()
|
||||
.stream()
|
||||
.filter(m -> UuidUtil.fromByteString(m.getAciBytes()).equals(editor))
|
||||
.map(DecryptedRequestingMember::getProfileKey)).findFirst();
|
||||
.filter(m -> UuidUtil.fromByteString(m.aciBytes).equals(editor))
|
||||
.map(m -> m.profileKey),
|
||||
change.newRequestingMembers.stream()
|
||||
.filter(m -> UuidUtil.fromByteString(m.aciBytes).equals(editor))
|
||||
.map(m -> m.profileKey)).findFirst();
|
||||
|
||||
if (editorProfileKeyBytes.isEmpty()) {
|
||||
return null;
|
||||
|
@ -630,8 +626,8 @@ class GroupV2Helper {
|
|||
.forGroup(GroupSecretParams.deriveFromMasterKey(groupMasterKey));
|
||||
|
||||
try {
|
||||
return groupOperations.decryptChange(GroupChange.parseFrom(signedGroupChange), true).orElse(null);
|
||||
} catch (VerificationFailedException | InvalidGroupStateException | InvalidProtocolBufferException e) {
|
||||
return groupOperations.decryptChange(GroupChange.ADAPTER.decode(signedGroupChange), true).orElse(null);
|
||||
} catch (VerificationFailedException | InvalidGroupStateException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,11 +70,8 @@ import org.whispersystems.signalservice.api.push.ServiceId;
|
|||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.Envelope;
|
||||
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
|
||||
import org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer;
|
||||
import org.whispersystems.signalservice.internal.serialize.SignalServiceMetadataProtobufSerializer;
|
||||
import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceContentProto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -213,7 +210,7 @@ public final class IncomingMessageHandler {
|
|||
}
|
||||
|
||||
private SignalServiceContent validate(
|
||||
SignalServiceProtos.Envelope envelope, SignalServiceCipherResult cipherResult, long serverDeliveredTimestamp
|
||||
Envelope envelope, SignalServiceCipherResult cipherResult, long serverDeliveredTimestamp
|
||||
) throws ProtocolInvalidKeyException, ProtocolInvalidMessageException, UnsupportedDataMessageException, InvalidMessageStructureException {
|
||||
final var content = cipherResult.getContent();
|
||||
final var envelopeMetadata = cipherResult.getMetadata();
|
||||
|
@ -236,21 +233,15 @@ public final class IncomingMessageHandler {
|
|||
final var metadata = new SignalServiceMetadata(new SignalServiceAddress(envelopeMetadata.getSourceServiceId(),
|
||||
Optional.ofNullable(envelopeMetadata.getSourceE164())),
|
||||
envelopeMetadata.getSourceDeviceId(),
|
||||
envelope.getTimestamp(),
|
||||
envelope.getServerTimestamp(),
|
||||
envelope.timestamp,
|
||||
envelope.serverTimestamp,
|
||||
serverDeliveredTimestamp,
|
||||
envelopeMetadata.getSealedSender(),
|
||||
envelope.getServerGuid(),
|
||||
envelope.serverGuid,
|
||||
Optional.ofNullable(envelopeMetadata.getGroupId()),
|
||||
envelopeMetadata.getDestinationServiceId().toString());
|
||||
|
||||
final var contentProto = SignalServiceContentProto.newBuilder()
|
||||
.setLocalAddress(SignalServiceAddressProtobufSerializer.toProtobuf(localAddress))
|
||||
.setMetadata(SignalServiceMetadataProtobufSerializer.toProtobuf(metadata))
|
||||
.setContent(content)
|
||||
.build();
|
||||
|
||||
return SignalServiceContent.createFromProto(contentProto);
|
||||
return SignalServiceContent.createFrom(localAddress, metadata, content);
|
||||
}
|
||||
|
||||
private List<HandleAction> checkAndHandleMessage(
|
||||
|
@ -635,23 +626,21 @@ public final class IncomingMessageHandler {
|
|||
if (syncMessage.getPniChangeNumber().isPresent()) {
|
||||
final var pniChangeNumber = syncMessage.getPniChangeNumber().get();
|
||||
logger.debug("Received PNI change number sync message, applying.");
|
||||
if (pniChangeNumber.hasIdentityKeyPair()
|
||||
&& pniChangeNumber.hasRegistrationId()
|
||||
&& pniChangeNumber.hasSignedPreKey()
|
||||
if (pniChangeNumber.identityKeyPair != null
|
||||
&& pniChangeNumber.registrationId != null
|
||||
&& pniChangeNumber.signedPreKey != null
|
||||
&& !envelope.getUpdatedPni().isEmpty()) {
|
||||
logger.debug("New PNI: {}", envelope.getUpdatedPni());
|
||||
try {
|
||||
final var updatedPni = PNI.parseOrThrow(envelope.getUpdatedPni());
|
||||
context.getAccountHelper()
|
||||
.setPni(updatedPni,
|
||||
new IdentityKeyPair(pniChangeNumber.getIdentityKeyPair().toByteArray()),
|
||||
pniChangeNumber.hasNewE164() ? pniChangeNumber.getNewE164() : null,
|
||||
pniChangeNumber.getRegistrationId(),
|
||||
new SignedPreKeyRecord(pniChangeNumber.getSignedPreKey().toByteArray()),
|
||||
pniChangeNumber.hasLastResortKyberPreKey()
|
||||
? new KyberPreKeyRecord(pniChangeNumber.getLastResortKyberPreKey()
|
||||
.toByteArray())
|
||||
: null);
|
||||
new IdentityKeyPair(pniChangeNumber.identityKeyPair.toByteArray()),
|
||||
pniChangeNumber.newE164,
|
||||
pniChangeNumber.registrationId,
|
||||
new SignedPreKeyRecord(pniChangeNumber.signedPreKey.toByteArray()),
|
||||
pniChangeNumber.lastResortKyberPreKey != null ? new KyberPreKeyRecord(
|
||||
pniChangeNumber.lastResortKyberPreKey.toByteArray()) : null);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to handle change number message", e);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.asamk.signal.manager.helper;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.asamk.signal.manager.api.Contact;
|
||||
import org.asamk.signal.manager.api.GroupId;
|
||||
import org.asamk.signal.manager.api.GroupNotFoundException;
|
||||
|
@ -54,6 +52,8 @@ import java.util.Set;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public class SendHelper {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SendHelper.class);
|
||||
|
@ -267,10 +267,10 @@ public class SendHelper {
|
|||
|
||||
final var senderKeyDistributionMessage = dependencies.getMessageSender()
|
||||
.getOrCreateNewGroupSession(group.getDistributionId());
|
||||
final var distributionBytes = ByteString.copyFrom(senderKeyDistributionMessage.serialize());
|
||||
final var distributionBytes = ByteString.of(senderKeyDistributionMessage.serialize());
|
||||
final var contentToSend = messageSendLogEntry.content()
|
||||
.toBuilder()
|
||||
.setSenderKeyDistributionMessage(distributionBytes)
|
||||
.newBuilder()
|
||||
.senderKeyDistributionMessage(distributionBytes)
|
||||
.build();
|
||||
|
||||
final var result = handleSendMessage(recipientId,
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy
|
|||
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.SyncMessage;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -58,20 +58,20 @@ public class SyncHelper {
|
|||
}
|
||||
|
||||
public void requestAllSyncData() {
|
||||
requestSyncData(SignalServiceProtos.SyncMessage.Request.Type.GROUPS);
|
||||
requestSyncData(SignalServiceProtos.SyncMessage.Request.Type.CONTACTS);
|
||||
requestSyncData(SignalServiceProtos.SyncMessage.Request.Type.BLOCKED);
|
||||
requestSyncData(SignalServiceProtos.SyncMessage.Request.Type.CONFIGURATION);
|
||||
requestSyncData(SyncMessage.Request.Type.GROUPS);
|
||||
requestSyncData(SyncMessage.Request.Type.CONTACTS);
|
||||
requestSyncData(SyncMessage.Request.Type.BLOCKED);
|
||||
requestSyncData(SyncMessage.Request.Type.CONFIGURATION);
|
||||
requestSyncKeys();
|
||||
requestSyncPniIdentity();
|
||||
}
|
||||
|
||||
public void requestSyncKeys() {
|
||||
requestSyncData(SignalServiceProtos.SyncMessage.Request.Type.KEYS);
|
||||
requestSyncData(SyncMessage.Request.Type.KEYS);
|
||||
}
|
||||
|
||||
public void requestSyncPniIdentity() {
|
||||
requestSyncData(SignalServiceProtos.SyncMessage.Request.Type.PNI_IDENTITY);
|
||||
requestSyncData(SyncMessage.Request.Type.PNI_IDENTITY);
|
||||
}
|
||||
|
||||
public void sendSyncFetchProfileMessage() {
|
||||
|
@ -346,8 +346,8 @@ public class SyncHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private void requestSyncData(final SignalServiceProtos.SyncMessage.Request.Type type) {
|
||||
var r = SignalServiceProtos.SyncMessage.Request.newBuilder().setType(type).build();
|
||||
private void requestSyncData(final SyncMessage.Request.Type type) {
|
||||
var r = new SyncMessage.Request.Builder().type(type).build();
|
||||
var message = SignalServiceSyncMessage.forRequest(new RequestMessage(r));
|
||||
context.getSendHelper().sendSyncMessage(message);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
|
||||
private final GroupIdV2 groupId;
|
||||
private final GroupMasterKey masterKey;
|
||||
private DistributionId distributionId;
|
||||
private final DistributionId distributionId;
|
||||
private boolean blocked;
|
||||
private DecryptedGroup group;
|
||||
private boolean permissionDenied;
|
||||
|
@ -84,7 +84,7 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return null;
|
||||
}
|
||||
return this.group.getTitle();
|
||||
return this.group.title;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,15 +92,15 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return null;
|
||||
}
|
||||
return this.group.getDescription();
|
||||
return this.group.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupInviteLinkUrl getGroupInviteLink() {
|
||||
if (this.group == null || this.group.getInviteLinkPassword().isEmpty() || (
|
||||
this.group.getAccessControl().getAddFromInviteLink() != AccessControl.AccessRequired.ANY
|
||||
&& this.group.getAccessControl().getAddFromInviteLink()
|
||||
!= AccessControl.AccessRequired.ADMINISTRATOR
|
||||
if (this.group == null || this.group.inviteLinkPassword.toByteArray().length == 0 || (
|
||||
this.group.accessControl != null
|
||||
&& this.group.accessControl.addFromInviteLink != AccessControl.AccessRequired.ANY
|
||||
&& this.group.accessControl.addFromInviteLink != AccessControl.AccessRequired.ADMINISTRATOR
|
||||
)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -113,9 +113,8 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return Set.of();
|
||||
}
|
||||
return group.getMembersList()
|
||||
.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.getAciBytes()))
|
||||
return group.members.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.aciBytes))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -125,9 +124,8 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return Set.of();
|
||||
}
|
||||
return group.getBannedMembersList()
|
||||
.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.getServiceIdBytes()))
|
||||
return group.bannedMembers.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.serviceIdBytes))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -137,9 +135,8 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return Set.of();
|
||||
}
|
||||
return group.getPendingMembersList()
|
||||
.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.getServiceIdBytes()))
|
||||
return group.pendingMembers.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.serviceIdBytes))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -149,9 +146,8 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return Set.of();
|
||||
}
|
||||
return group.getRequestingMembersList()
|
||||
.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.getAciBytes()))
|
||||
return group.requestingMembers.stream()
|
||||
.map(m -> ServiceId.parseOrThrow(m.aciBytes))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -161,11 +157,10 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
if (this.group == null) {
|
||||
return Set.of();
|
||||
}
|
||||
return group.getMembersList()
|
||||
.stream()
|
||||
.filter(m -> m.getRole() == Member.Role.ADMINISTRATOR)
|
||||
.map(m -> new RecipientAddress(ServiceId.ACI.parseOrNull(m.getAciBytes()),
|
||||
ServiceId.PNI.parseOrNull(m.getPniBytes()),
|
||||
return group.members.stream()
|
||||
.filter(m -> m.role == Member.Role.ADMINISTRATOR)
|
||||
.map(m -> new RecipientAddress(ServiceId.ACI.parseOrNull(m.aciBytes),
|
||||
ServiceId.PNI.parseOrNull(m.pniBytes),
|
||||
null))
|
||||
.map(recipientResolver::resolveRecipient)
|
||||
.collect(Collectors.toSet());
|
||||
|
@ -183,26 +178,26 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
|
||||
@Override
|
||||
public int getMessageExpirationTimer() {
|
||||
return this.group != null && this.group.hasDisappearingMessagesTimer()
|
||||
? this.group.getDisappearingMessagesTimer().getDuration()
|
||||
return this.group != null && this.group.disappearingMessagesTimer != null
|
||||
? this.group.disappearingMessagesTimer.duration
|
||||
: 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnouncementGroup() {
|
||||
return this.group != null && this.group.getIsAnnouncementGroup() == EnabledState.ENABLED;
|
||||
return this.group != null && this.group.isAnnouncementGroup == EnabledState.ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupPermission getPermissionAddMember() {
|
||||
final var accessControl = getAccessControl();
|
||||
return accessControl == null ? GroupPermission.EVERY_MEMBER : toGroupPermission(accessControl.getMembers());
|
||||
return accessControl == null ? GroupPermission.EVERY_MEMBER : toGroupPermission(accessControl.members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupPermission getPermissionEditDetails() {
|
||||
final var accessControl = getAccessControl();
|
||||
return accessControl == null ? GroupPermission.EVERY_MEMBER : toGroupPermission(accessControl.getAttributes());
|
||||
return accessControl == null ? GroupPermission.EVERY_MEMBER : toGroupPermission(accessControl.attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -219,11 +214,11 @@ public final class GroupInfoV2 extends GroupInfo {
|
|||
}
|
||||
|
||||
private AccessControl getAccessControl() {
|
||||
if (this.group == null || !this.group.hasAccessControl()) {
|
||||
if (this.group == null || this.group.accessControl == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.group.getAccessControl();
|
||||
return this.group.accessControl;
|
||||
}
|
||||
|
||||
private static GroupPermission toGroupPermission(final AccessControl.AccessRequired permission) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.asamk.signal.manager.storage.groups;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.asamk.signal.manager.api.GroupId;
|
||||
import org.asamk.signal.manager.api.GroupIdV1;
|
||||
import org.asamk.signal.manager.api.GroupIdV2;
|
||||
|
@ -19,6 +17,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.whispersystems.signalservice.api.push.DistributionId;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -295,7 +294,7 @@ public class GroupStore {
|
|||
if (groupV2.getGroup() == null) {
|
||||
statement.setNull(4, Types.NUMERIC);
|
||||
} else {
|
||||
statement.setBytes(4, groupV2.getGroup().toByteArray());
|
||||
statement.setBytes(4, groupV2.getGroup().encode());
|
||||
}
|
||||
statement.setBytes(5, UuidUtil.toByteArray(groupV2.getDistributionId().asUuid()));
|
||||
statement.setBoolean(6, groupV2.isBlocked());
|
||||
|
@ -349,12 +348,12 @@ public class GroupStore {
|
|||
final var permissionDenied = resultSet.getBoolean("permission_denied");
|
||||
return new GroupInfoV2(GroupId.v2(groupId),
|
||||
new GroupMasterKey(masterKey),
|
||||
groupData == null ? null : DecryptedGroup.parseFrom(groupData),
|
||||
groupData == null ? null : DecryptedGroup.ADAPTER.decode(groupData),
|
||||
DistributionId.from(UuidUtil.parseOrThrow(distributionId)),
|
||||
blocked,
|
||||
permissionDenied,
|
||||
recipientResolver);
|
||||
} catch (InvalidInputException | InvalidProtocolBufferException e) {
|
||||
} catch (InvalidInputException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ public class LegacyGroupStore {
|
|||
return null;
|
||||
}
|
||||
try (var stream = new FileInputStream(groupFile)) {
|
||||
return DecryptedGroup.parseFrom(stream);
|
||||
return DecryptedGroup.ADAPTER.decode(stream);
|
||||
} catch (IOException ignored) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ package org.asamk.signal.manager.storage.sendLog;
|
|||
|
||||
import org.asamk.signal.manager.api.GroupId;
|
||||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.Content;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record MessageSendLogEntry(
|
||||
Optional<GroupId> groupId, SignalServiceProtos.Content content, ContentHint contentHint, boolean urgent
|
||||
Optional<GroupId> groupId, Content content, ContentHint contentHint, boolean urgent
|
||||
) {}
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.Content;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
|
@ -267,7 +267,7 @@ public class MessageSendLogStore implements AutoCloseable {
|
|||
private long insert(
|
||||
final List<RecipientDevices> recipientDevices,
|
||||
final long sentTimestamp,
|
||||
final SignalServiceProtos.Content content,
|
||||
final Content content,
|
||||
final ContentHint contentHint,
|
||||
final boolean urgent
|
||||
) {
|
||||
|
@ -284,7 +284,7 @@ public class MessageSendLogStore implements AutoCloseable {
|
|||
try (final var statement = connection.prepareStatement(sql)) {
|
||||
statement.setLong(1, sentTimestamp);
|
||||
statement.setBytes(2, groupId);
|
||||
statement.setBytes(3, content.toByteArray());
|
||||
statement.setBytes(3, content.encode());
|
||||
statement.setInt(4, contentHint.getType());
|
||||
statement.setBoolean(5, urgent);
|
||||
final var generatedKey = Utils.executeQueryForOptional(statement, Utils::getIdMapper);
|
||||
|
@ -308,17 +308,15 @@ public class MessageSendLogStore implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] getGroupId(final SignalServiceProtos.Content content) {
|
||||
private byte[] getGroupId(final Content content) {
|
||||
try {
|
||||
return !content.hasDataMessage()
|
||||
return content.dataMessage == null
|
||||
? null
|
||||
: content.getDataMessage().hasGroup()
|
||||
? content.getDataMessage().getGroup().getId().toByteArray()
|
||||
: content.getDataMessage().hasGroupV2()
|
||||
? GroupUtils.getGroupIdV2(new GroupMasterKey(content.getDataMessage()
|
||||
.getGroupV2()
|
||||
.getMasterKey()
|
||||
.toByteArray())).serialize()
|
||||
: content.dataMessage.group != null && content.dataMessage.group.id != null
|
||||
? content.dataMessage.group.id.toByteArray()
|
||||
: content.dataMessage.groupV2 != null && content.dataMessage.groupV2.masterKey != null
|
||||
? GroupUtils.getGroupIdV2(new GroupMasterKey(content.dataMessage.groupV2.masterKey.toByteArray()))
|
||||
.serialize()
|
||||
: null;
|
||||
} catch (InvalidInputException e) {
|
||||
logger.warn("Failed to parse groupId id from content");
|
||||
|
@ -385,9 +383,9 @@ public class MessageSendLogStore implements AutoCloseable {
|
|||
|
||||
private MessageSendLogEntry getMessageSendLogEntryFromResultSet(ResultSet resultSet) throws SQLException {
|
||||
final var groupId = Optional.ofNullable(resultSet.getBytes("group_id")).map(GroupId::unknownVersion);
|
||||
final SignalServiceProtos.Content content;
|
||||
final Content content;
|
||||
try {
|
||||
content = SignalServiceProtos.Content.parseFrom(resultSet.getBinaryStream("content"));
|
||||
content = Content.ADAPTER.decode(resultSet.getBinaryStream("content"));
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to parse content from message send log", e);
|
||||
return null;
|
||||
|
|
|
@ -6,7 +6,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
|||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.Envelope;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
@ -34,7 +34,7 @@ public class MessageCacheUtils {
|
|||
}
|
||||
if (version >= 9) {
|
||||
final var serverReceivedTimestamp = in.readLong();
|
||||
final var envelope = SignalServiceProtos.Envelope.parseFrom(in.readAllBytes());
|
||||
final var envelope = Envelope.ADAPTER.decode(in.readAllBytes());
|
||||
return new SignalServiceEnvelope(envelope, serverReceivedTimestamp);
|
||||
} else {
|
||||
var type = in.readInt();
|
||||
|
@ -114,7 +114,7 @@ public class MessageCacheUtils {
|
|||
try (var out = new DataOutputStream(f)) {
|
||||
out.writeInt(CURRENT_VERSION); // version
|
||||
out.writeLong(envelope.getServerDeliveredTimestamp());
|
||||
envelope.getProto().writeTo(out);
|
||||
envelope.getProto().encode(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package org.asamk.signal.manager.util;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.libsignal.protocol.IdentityKey;
|
||||
import org.signal.libsignal.protocol.IdentityKeyPair;
|
||||
import org.signal.libsignal.protocol.ecc.ECPrivateKey;
|
||||
import org.signal.libsignal.protocol.ecc.ECPublicKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.PaymentAddress;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public class PaymentUtils {
|
||||
|
||||
|
@ -20,16 +20,13 @@ public class PaymentUtils {
|
|||
/**
|
||||
* Signs the supplied address bytes with the {@link IdentityKeyPair}'s private key and returns a proto that includes it, and it's signature.
|
||||
*/
|
||||
public static SignalServiceProtos.PaymentAddress signPaymentsAddress(
|
||||
public static PaymentAddress signPaymentsAddress(
|
||||
byte[] publicAddressBytes, ECPrivateKey privateKey
|
||||
) {
|
||||
byte[] signature = privateKey.calculateSignature(publicAddressBytes);
|
||||
|
||||
return SignalServiceProtos.PaymentAddress.newBuilder()
|
||||
.setMobileCoinAddress(SignalServiceProtos.PaymentAddress.MobileCoinAddress.newBuilder()
|
||||
.setAddress(ByteString.copyFrom(publicAddressBytes))
|
||||
.setSignature(ByteString.copyFrom(signature)))
|
||||
.build();
|
||||
return new PaymentAddress.Builder().mobileCoinAddress(new PaymentAddress.MobileCoinAddress.Builder().address(
|
||||
ByteString.of(publicAddressBytes)).signature(ByteString.of(signature)).build()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,15 +35,16 @@ public class PaymentUtils {
|
|||
* Returns the validated bytes if so, otherwise returns null.
|
||||
*/
|
||||
public static byte[] verifyPaymentsAddress(
|
||||
SignalServiceProtos.PaymentAddress paymentAddress, ECPublicKey publicKey
|
||||
PaymentAddress paymentAddress, ECPublicKey publicKey
|
||||
) {
|
||||
if (!paymentAddress.hasMobileCoinAddress()) {
|
||||
final var mobileCoinAddress = paymentAddress.mobileCoinAddress;
|
||||
if (mobileCoinAddress == null || mobileCoinAddress.address == null || mobileCoinAddress.signature == null) {
|
||||
logger.debug("Got payment address without mobile coin address, ignoring.");
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] bytes = paymentAddress.getMobileCoinAddress().getAddress().toByteArray();
|
||||
byte[] signature = paymentAddress.getMobileCoinAddress().getSignature().toByteArray();
|
||||
byte[] bytes = mobileCoinAddress.address.toByteArray();
|
||||
byte[] signature = mobileCoinAddress.signature.toByteArray();
|
||||
|
||||
if (signature.length != 64 || !publicKey.verifySignature(bytes, signature)) {
|
||||
logger.debug("Got mobile coin address with invalid signature, ignoring.");
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.asamk.signal.manager.util;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.asamk.signal.manager.api.Pair;
|
||||
import org.asamk.signal.manager.api.Profile;
|
||||
import org.signal.libsignal.protocol.IdentityKey;
|
||||
|
@ -13,7 +11,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.PaymentAddress;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
@ -117,10 +115,10 @@ public class ProfileUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
SignalServiceProtos.PaymentAddress paymentAddress;
|
||||
PaymentAddress paymentAddress;
|
||||
try {
|
||||
paymentAddress = SignalServiceProtos.PaymentAddress.parseFrom(decrypted);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
paymentAddress = PaymentAddress.ADAPTER.decode(decrypted);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to parse payment address", e);
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue