use of org.whispersystems.signalservice.api.messages.SignalServiceDataMessage in project Signal-Android by WhisperSystems.
the class MessageContentProcessor method shouldIgnore.
private boolean shouldIgnore(@NonNull SignalServiceContent content, @NonNull Recipient sender, @NonNull Recipient conversation) throws BadGroupIdException {
if (content.getDataMessage().isPresent()) {
SignalServiceDataMessage message = content.getDataMessage().get();
if (conversation.isGroup() && conversation.isBlocked()) {
return true;
} else if (conversation.isGroup()) {
GroupDatabase groupDatabase = SignalDatabase.groups();
Optional<GroupId> groupId = GroupUtil.idFromGroupContext(message.getGroupContext());
if (groupId.isPresent() && groupId.get().isV1() && message.isGroupV1Update() && groupDatabase.groupExists(groupId.get().requireV1().deriveV2MigrationGroupId())) {
warn(String.valueOf(content.getTimestamp()), "Ignoring V1 update for a group we've already migrated to V2.");
return true;
}
if (groupId.isPresent() && groupDatabase.isUnknownGroup(groupId.get())) {
return sender.isBlocked();
}
boolean isTextMessage = message.getBody().isPresent();
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getSticker().isPresent();
boolean isExpireMessage = message.isExpirationUpdate();
boolean isGv2Update = message.isGroupV2Update();
boolean isContentMessage = !message.isGroupV1Update() && !isGv2Update && !isExpireMessage && (isTextMessage || isMediaMessage);
boolean isGroupActive = groupId.isPresent() && groupDatabase.isActive(groupId.get());
boolean isLeaveMessage = message.getGroupContext().isPresent() && message.getGroupContext().get().getGroupV1Type() == SignalServiceGroup.Type.QUIT;
return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage && !isGv2Update);
} else {
return sender.isBlocked();
}
} else if (content.getCallMessage().isPresent()) {
return sender.isBlocked();
} else if (content.getTypingMessage().isPresent()) {
if (sender.isBlocked()) {
return true;
}
if (content.getTypingMessage().get().getGroupId().isPresent()) {
GroupId groupId = GroupId.push(content.getTypingMessage().get().getGroupId().get());
Recipient groupRecipient = Recipient.externalPossiblyMigratedGroup(context, groupId);
if (groupRecipient.isBlocked() || !groupRecipient.isActiveGroup()) {
return true;
} else {
Optional<GroupRecord> groupRecord = SignalDatabase.groups().getGroup(groupId);
return groupRecord.isPresent() && groupRecord.get().isAnnouncementGroup() && !groupRecord.get().getAdmins().contains(sender);
}
}
}
return false;
}
use of org.whispersystems.signalservice.api.messages.SignalServiceDataMessage in project libsignal-service-java by signalapp.
the class SignalServiceCipher method createSignalServiceMessage.
private SignalServiceDataMessage createSignalServiceMessage(Metadata metadata, DataMessage content) throws ProtocolInvalidMessageException, UnsupportedDataMessageException {
SignalServiceGroup groupInfo = createGroupInfo(content);
List<SignalServiceAttachment> attachments = new LinkedList<>();
boolean endSession = ((content.getFlags() & DataMessage.Flags.END_SESSION_VALUE) != 0);
boolean expirationUpdate = ((content.getFlags() & DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE) != 0);
boolean profileKeyUpdate = ((content.getFlags() & DataMessage.Flags.PROFILE_KEY_UPDATE_VALUE) != 0);
SignalServiceDataMessage.Quote quote = createQuote(content);
List<SharedContact> sharedContacts = createSharedContacts(content);
List<Preview> previews = createPreviews(content);
Sticker sticker = createSticker(content);
if (content.getRequiredProtocolVersion() > DataMessage.ProtocolVersion.CURRENT.getNumber()) {
throw new UnsupportedDataMessageException(DataMessage.ProtocolVersion.CURRENT.getNumber(), content.getRequiredProtocolVersion(), metadata.getSender().getIdentifier(), metadata.getSenderDevice(), Optional.fromNullable(groupInfo));
}
for (AttachmentPointer pointer : content.getAttachmentsList()) {
attachments.add(createAttachmentPointer(pointer));
}
if (content.hasTimestamp() && content.getTimestamp() != metadata.getTimestamp()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Timestamps don't match: " + content.getTimestamp() + " vs " + metadata.getTimestamp()), metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
return new SignalServiceDataMessage(metadata.getTimestamp(), groupInfo, attachments, content.getBody(), endSession, content.getExpireTimer(), expirationUpdate, content.hasProfileKey() ? content.getProfileKey().toByteArray() : null, profileKeyUpdate, quote, sharedContacts, previews, sticker, content.getIsViewOnce());
}
use of org.whispersystems.signalservice.api.messages.SignalServiceDataMessage in project libsignal-service-java by signalapp.
the class SignalServiceCipher method createSynchronizeMessage.
private SignalServiceSyncMessage createSynchronizeMessage(Metadata metadata, SyncMessage content) throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException {
if (content.hasSent()) {
SyncMessage.Sent sentContent = content.getSent();
SignalServiceDataMessage dataMessage = createSignalServiceMessage(metadata, sentContent.getMessage());
Optional<SignalServiceAddress> address = SignalServiceAddress.isValidAddress(sentContent.getDestinationUuid(), sentContent.getDestinationE164()) ? Optional.of(new SignalServiceAddress(UuidUtil.parseOrNull(sentContent.getDestinationUuid()), sentContent.getDestinationE164())) : Optional.<SignalServiceAddress>absent();
Map<SignalServiceAddress, Boolean> unidentifiedStatuses = new HashMap<>();
if (!address.isPresent() && !dataMessage.getGroupInfo().isPresent()) {
throw new ProtocolInvalidMessageException(new InvalidMessageException("SyncMessage missing both destination and group ID!"), null, 0);
}
for (SyncMessage.Sent.UnidentifiedDeliveryStatus status : sentContent.getUnidentifiedStatusList()) {
if (SignalServiceAddress.isValidAddress(status.getDestinationUuid(), status.getDestinationE164())) {
SignalServiceAddress recipient = new SignalServiceAddress(UuidUtil.parseOrNull(status.getDestinationUuid()), status.getDestinationE164());
unidentifiedStatuses.put(recipient, status.getUnidentified());
} else {
Log.w(TAG, "Encountered an invalid UnidentifiedDeliveryStatus in a SentTranscript! Ignoring.");
}
}
return SignalServiceSyncMessage.forSentTranscript(new SentTranscriptMessage(address, sentContent.getTimestamp(), dataMessage, sentContent.getExpirationStartTimestamp(), unidentifiedStatuses, sentContent.getIsRecipientUpdate()));
}
if (content.hasRequest()) {
return SignalServiceSyncMessage.forRequest(new RequestMessage(content.getRequest()));
}
if (content.getReadList().size() > 0) {
List<ReadMessage> readMessages = new LinkedList<>();
for (SyncMessage.Read read : content.getReadList()) {
if (SignalServiceAddress.isValidAddress(read.getSenderUuid(), read.getSenderE164())) {
SignalServiceAddress address = new SignalServiceAddress(UuidUtil.parseOrNull(read.getSenderUuid()), read.getSenderE164());
readMessages.add(new ReadMessage(address, read.getTimestamp()));
} else {
Log.w(TAG, "Encountered an invalid ReadMessage! Ignoring.");
}
}
return SignalServiceSyncMessage.forRead(readMessages);
}
if (content.hasViewOnceOpen()) {
if (SignalServiceAddress.isValidAddress(content.getViewOnceOpen().getSenderUuid(), content.getViewOnceOpen().getSenderE164())) {
SignalServiceAddress address = new SignalServiceAddress(UuidUtil.parseOrNull(content.getViewOnceOpen().getSenderUuid()), content.getViewOnceOpen().getSenderE164());
ViewOnceOpenMessage timerRead = new ViewOnceOpenMessage(address, content.getViewOnceOpen().getTimestamp());
return SignalServiceSyncMessage.forViewOnceOpen(timerRead);
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("ViewOnceOpen message has no sender!"), null, 0);
}
}
if (content.hasVerified()) {
if (SignalServiceAddress.isValidAddress(content.getVerified().getDestinationUuid(), content.getVerified().getDestinationE164())) {
try {
Verified verified = content.getVerified();
SignalServiceAddress destination = new SignalServiceAddress(UuidUtil.parseOrNull(verified.getDestinationUuid()), verified.getDestinationE164());
IdentityKey identityKey = new IdentityKey(verified.getIdentityKey().toByteArray(), 0);
VerifiedState verifiedState;
if (verified.getState() == Verified.State.DEFAULT) {
verifiedState = VerifiedState.DEFAULT;
} else if (verified.getState() == Verified.State.VERIFIED) {
verifiedState = VerifiedState.VERIFIED;
} else if (verified.getState() == Verified.State.UNVERIFIED) {
verifiedState = VerifiedState.UNVERIFIED;
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Unknown state: " + verified.getState().getNumber()), metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
return SignalServiceSyncMessage.forVerified(new VerifiedMessage(destination, identityKey, verifiedState, System.currentTimeMillis()));
} catch (InvalidKeyException e) {
throw new ProtocolInvalidKeyException(e, metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
} else {
throw new ProtocolInvalidMessageException(new InvalidMessageException("Verified message has no sender!"), null, 0);
}
}
if (content.getStickerPackOperationList().size() > 0) {
List<StickerPackOperationMessage> operations = new LinkedList<>();
for (SyncMessage.StickerPackOperation operation : content.getStickerPackOperationList()) {
byte[] packId = operation.hasPackId() ? operation.getPackId().toByteArray() : null;
byte[] packKey = operation.hasPackKey() ? operation.getPackKey().toByteArray() : null;
StickerPackOperationMessage.Type type = null;
if (operation.hasType()) {
switch(operation.getType()) {
case INSTALL:
type = StickerPackOperationMessage.Type.INSTALL;
break;
case REMOVE:
type = StickerPackOperationMessage.Type.REMOVE;
break;
}
}
operations.add(new StickerPackOperationMessage(packId, packKey, type));
}
return SignalServiceSyncMessage.forStickerPackOperations(operations);
}
if (content.hasBlocked()) {
List<String> numbers = content.getBlocked().getNumbersList();
List<String> uuids = content.getBlocked().getUuidsList();
List<SignalServiceAddress> addresses = new ArrayList<>(numbers.size() + uuids.size());
List<byte[]> groupIds = new ArrayList<>(content.getBlocked().getGroupIdsList().size());
for (String e164 : numbers) {
Optional<SignalServiceAddress> address = SignalServiceAddress.fromRaw(null, e164);
if (address.isPresent()) {
addresses.add(address.get());
}
}
for (String uuid : uuids) {
Optional<SignalServiceAddress> address = SignalServiceAddress.fromRaw(uuid, null);
if (address.isPresent()) {
addresses.add(address.get());
}
}
for (ByteString groupId : content.getBlocked().getGroupIdsList()) {
groupIds.add(groupId.toByteArray());
}
return SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groupIds));
}
if (content.hasConfiguration()) {
Boolean readReceipts = content.getConfiguration().hasReadReceipts() ? content.getConfiguration().getReadReceipts() : null;
Boolean unidentifiedDeliveryIndicators = content.getConfiguration().hasUnidentifiedDeliveryIndicators() ? content.getConfiguration().getUnidentifiedDeliveryIndicators() : null;
Boolean typingIndicators = content.getConfiguration().hasTypingIndicators() ? content.getConfiguration().getTypingIndicators() : null;
Boolean linkPreviews = content.getConfiguration().hasLinkPreviews() ? content.getConfiguration().getLinkPreviews() : null;
return SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.fromNullable(readReceipts), Optional.fromNullable(unidentifiedDeliveryIndicators), Optional.fromNullable(typingIndicators), Optional.fromNullable(linkPreviews)));
}
if (content.hasFetchLatest() && content.getFetchLatest().hasType()) {
switch(content.getFetchLatest().getType()) {
case LOCAL_PROFILE:
return SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.LOCAL_PROFILE);
case STORAGE_MANIFEST:
return SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.STORAGE_MANIFEST);
}
}
return SignalServiceSyncMessage.empty();
}
use of org.whispersystems.signalservice.api.messages.SignalServiceDataMessage in project Signal-Android by signalapp.
the class ReactionSendJob method deliver.
@NonNull
private List<Recipient> deliver(@NonNull Recipient conversationRecipient, @NonNull List<Recipient> destinations, @NonNull Recipient targetAuthor, long targetSentTimestamp) throws IOException, UntrustedIdentityException {
SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder().withTimestamp(System.currentTimeMillis()).withReaction(buildReaction(context, reaction, remove, targetAuthor, targetSentTimestamp));
if (conversationRecipient.isGroup()) {
GroupUtil.setDataMessageGroupContext(context, dataMessageBuilder, conversationRecipient.requireGroupId().requirePush());
}
SignalServiceDataMessage dataMessage = dataMessageBuilder.build();
List<Recipient> nonSelfDestinations = destinations.stream().filter(r -> !r.isSelf()).collect(Collectors.toList());
boolean includesSelf = nonSelfDestinations.size() != destinations.size();
List<SendMessageResult> results = GroupSendUtil.sendResendableDataMessage(context, conversationRecipient.getGroupId().transform(GroupId::requireV2).orNull(), nonSelfDestinations, false, ContentHint.RESENDABLE, messageId, dataMessage);
if (includesSelf) {
results.add(ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage));
}
return GroupSendJobHelper.getCompletedSends(destinations, results);
}
use of org.whispersystems.signalservice.api.messages.SignalServiceDataMessage in project Signal-Android by signalapp.
the class PushTextSendJob method deliver.
private boolean deliver(SmsMessageRecord message) throws UntrustedIdentityException, InsecureFallbackApprovalException, UndeliverableMessageException, IOException {
try {
rotateSenderCertificateIfNecessary();
Recipient messageRecipient = message.getIndividualRecipient().resolve();
if (messageRecipient.isUnregistered()) {
throw new UndeliverableMessageException(messageRecipient.getId() + " not registered!");
}
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
SignalServiceAddress address = RecipientUtil.toSignalServiceAddress(context, messageRecipient);
Optional<byte[]> profileKey = getProfileKey(messageRecipient);
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, messageRecipient);
log(TAG, String.valueOf(message.getDateSent()), "Have access key to use: " + unidentifiedAccess.isPresent());
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder().withTimestamp(message.getDateSent()).withBody(message.getBody()).withExpiration((int) (message.getExpiresIn() / 1000)).withProfileKey(profileKey.orNull()).asEndSessionMessage(message.isEndSession()).build();
if (Util.equals(SignalStore.account().getAci(), address.getServiceId())) {
Optional<UnidentifiedAccessPair> syncAccess = UnidentifiedAccessUtil.getAccessForSync(context);
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);
SendMessageResult result = messageSender.sendSyncMessage(textSecureMessage);
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false));
return syncAccess.isPresent();
} else {
SignalLocalMetrics.IndividualMessageSend.onDeliveryStarted(messageId);
SendMessageResult result = messageSender.sendDataMessage(address, unidentifiedAccess, ContentHint.RESENDABLE, textSecureMessage, new MetricEventListener(messageId));
SignalDatabase.messageLog().insertIfPossible(messageRecipient.getId(), message.getDateSent(), result, ContentHint.RESENDABLE, new MessageId(messageId, false));
return result.getSuccess().isUnidentified();
}
} catch (UnregisteredUserException e) {
warn(TAG, "Failure", e);
throw new InsecureFallbackApprovalException(e);
} catch (ServerRejectedException e) {
throw new UndeliverableMessageException(e);
}
}
Aggregations