use of org.whispersystems.signalservice.api.crypto.UntrustedIdentityException in project libsignal-service-java by signalapp.
the class SignalServiceMessageSender method getEncryptedMessage.
private OutgoingPushMessage getEncryptedMessage(PushServiceSocket socket, SignalServiceAddress recipient, Optional<UnidentifiedAccess> unidentifiedAccess, int deviceId, byte[] plaintext) throws IOException, InvalidKeyException, UntrustedIdentityException {
SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(recipient.getIdentifier(), deviceId);
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, store, null);
if (!store.containsSession(signalProtocolAddress)) {
try {
List<PreKeyBundle> preKeys = socket.getPreKeys(recipient, unidentifiedAccess, deviceId);
for (PreKeyBundle preKey : preKeys) {
try {
SignalProtocolAddress preKeyAddress = new SignalProtocolAddress(recipient.getIdentifier(), preKey.getDeviceId());
SessionBuilder sessionBuilder = new SessionBuilder(store, preKeyAddress);
sessionBuilder.process(preKey);
} catch (org.whispersystems.libsignal.UntrustedIdentityException e) {
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey());
}
}
if (eventListener.isPresent()) {
eventListener.get().onSecurityEvent(recipient);
}
} catch (InvalidKeyException e) {
throw new IOException(e);
}
}
try {
return cipher.encrypt(signalProtocolAddress, unidentifiedAccess, plaintext);
} catch (org.whispersystems.libsignal.UntrustedIdentityException e) {
throw new UntrustedIdentityException("Untrusted on send", recipient.getIdentifier(), e.getUntrustedIdentity());
}
}
use of org.whispersystems.signalservice.api.crypto.UntrustedIdentityException 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.crypto.UntrustedIdentityException in project Signal-Android by signalapp.
the class PushGroupSendJob method onPushSend.
@Override
public void onPushSend() throws IOException, MmsException, NoSuchMessageException, RetryLaterException {
SignalLocalMetrics.GroupMessageSend.onJobStarted(messageId);
MessageDatabase database = SignalDatabase.mms();
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
long threadId = database.getMessageRecord(messageId).getThreadId();
Set<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
Set<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
ApplicationDependencies.getJobManager().cancelAllInQueue(TypingSendJob.getQueue(threadId));
if (database.isSent(messageId)) {
log(TAG, String.valueOf(message.getSentTimeMillis()), "Message " + messageId + " was already sent. Ignoring.");
return;
}
Recipient groupRecipient = message.getRecipient().resolve();
if (!groupRecipient.isPushGroup()) {
throw new MmsException("Message recipient isn't a group!");
}
if (groupRecipient.isPushV1Group()) {
throw new MmsException("No GV1 messages can be sent anymore!");
}
try {
log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments()));
if (!groupRecipient.resolve().isProfileSharing() && !database.isGroupQuitMessage(messageId)) {
RecipientUtil.shareProfileIfFirstSecureMessage(context, groupRecipient);
}
List<Recipient> target;
if (filterRecipient != null)
target = Collections.singletonList(Recipient.resolved(filterRecipient));
else if (!existingNetworkFailures.isEmpty())
target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList();
else
target = Stream.of(getGroupMessageRecipients(groupRecipient.requireGroupId(), messageId)).distinctBy(Recipient::getId).toList();
RecipientAccessList accessList = new RecipientAccessList(target);
List<SendMessageResult> results = deliver(message, groupRecipient, target);
Log.i(TAG, JobLogger.format(this, "Finished send."));
List<NetworkFailure> networkFailures = Stream.of(results).filter(SendMessageResult::isNetworkFailure).map(result -> new NetworkFailure(accessList.requireIdByAddress(result.getAddress()))).toList();
List<IdentityKeyMismatch> identityMismatches = Stream.of(results).filter(result -> result.getIdentityFailure() != null).map(result -> new IdentityKeyMismatch(accessList.requireIdByAddress(result.getAddress()), result.getIdentityFailure().getIdentityKey())).toList();
ProofRequiredException proofRequired = Stream.of(results).filter(r -> r.getProofRequiredFailure() != null).findLast().map(SendMessageResult::getProofRequiredFailure).orElse(null);
List<SendMessageResult> successes = Stream.of(results).filter(result -> result.getSuccess() != null).toList();
List<Pair<RecipientId, Boolean>> successUnidentifiedStatus = Stream.of(successes).map(result -> new Pair<>(accessList.requireIdByAddress(result.getAddress()), result.getSuccess().isUnidentified())).toList();
Set<RecipientId> successIds = Stream.of(successUnidentifiedStatus).map(Pair::first).collect(Collectors.toSet());
List<NetworkFailure> resolvedNetworkFailures = Stream.of(existingNetworkFailures).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
List<IdentityKeyMismatch> resolvedIdentityFailures = Stream.of(existingIdentityMismatches).filter(failure -> successIds.contains(failure.getRecipientId(context))).toList();
List<RecipientId> unregisteredRecipients = Stream.of(results).filter(SendMessageResult::isUnregisteredFailure).map(result -> RecipientId.from(result.getAddress())).toList();
if (networkFailures.size() > 0 || identityMismatches.size() > 0 || proofRequired != null || unregisteredRecipients.size() > 0) {
Log.w(TAG, String.format(Locale.US, "Failed to send to some recipients. Network: %d, Identity: %d, ProofRequired: %s, Unregistered: %d", networkFailures.size(), identityMismatches.size(), proofRequired != null, unregisteredRecipients.size()));
}
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
for (RecipientId unregistered : unregisteredRecipients) {
recipientDatabase.markUnregistered(unregistered);
}
existingNetworkFailures.removeAll(resolvedNetworkFailures);
existingNetworkFailures.addAll(networkFailures);
database.setNetworkFailures(messageId, existingNetworkFailures);
existingIdentityMismatches.removeAll(resolvedIdentityFailures);
existingIdentityMismatches.addAll(identityMismatches);
database.setMismatchedIdentities(messageId, existingIdentityMismatches);
SignalDatabase.groupReceipts().setUnidentified(successUnidentifiedStatus, messageId);
if (proofRequired != null) {
handleProofRequiredException(proofRequired, groupRecipient, threadId, messageId, true);
}
if (existingNetworkFailures.isEmpty() && networkFailures.isEmpty() && identityMismatches.isEmpty() && existingIdentityMismatches.isEmpty()) {
database.markAsSent(messageId, true);
markAttachmentsUploaded(messageId, message);
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
database.markExpireStarted(messageId);
ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, message.getExpiresIn());
}
if (message.isViewOnce()) {
SignalDatabase.attachments().deleteAttachmentFilesForViewOnceMessage(messageId);
}
} else if (!identityMismatches.isEmpty()) {
Log.w(TAG, "Failing because there were " + identityMismatches.size() + " identity mismatches.");
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
Set<RecipientId> mismatchRecipientIds = Stream.of(identityMismatches).map(mismatch -> mismatch.getRecipientId(context)).collect(Collectors.toSet());
RetrieveProfileJob.enqueue(mismatchRecipientIds);
} else if (!networkFailures.isEmpty()) {
Log.w(TAG, "Retrying because there were " + networkFailures.size() + " network failures.");
throw new RetryLaterException();
}
} catch (UntrustedIdentityException | UndeliverableMessageException e) {
warn(TAG, String.valueOf(message.getSentTimeMillis()), e);
database.markAsSentFailed(messageId);
notifyMediaMessageDeliveryFailed(context, messageId);
}
SignalLocalMetrics.GroupMessageSend.onJobFinished(messageId);
}
use of org.whispersystems.signalservice.api.crypto.UntrustedIdentityException in project Signal-Android by signalapp.
the class GroupCallUpdateSendJob method deliver.
@NonNull
private List<Recipient> deliver(@NonNull Recipient conversationRecipient, @NonNull List<Recipient> destinations) throws IOException, UntrustedIdentityException {
SignalServiceDataMessage.Builder dataMessageBuilder = SignalServiceDataMessage.newBuilder().withTimestamp(System.currentTimeMillis()).withGroupCallUpdate(new SignalServiceDataMessage.GroupCallUpdate(eraId));
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.sendUnresendableDataMessage(context, conversationRecipient.requireGroupId().requireV2(), nonSelfDestinations, false, ContentHint.DEFAULT, dataMessage);
if (includesSelf) {
results.add(ApplicationDependencies.getSignalServiceMessageSender().sendSyncMessage(dataMessage));
}
return GroupSendJobHelper.getCompletedSends(destinations, results);
}
use of org.whispersystems.signalservice.api.crypto.UntrustedIdentityException in project Signal-Android by signalapp.
the class NullMessageSendJob method onRun.
@Override
protected void onRun() throws Exception {
Recipient recipient = Recipient.resolved(recipientId);
if (recipient.isGroup()) {
Log.w(TAG, "Groups are not supported!");
return;
}
if (recipient.isUnregistered()) {
Log.w(TAG, recipient.getId() + " not registered!");
}
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
SignalServiceAddress address = RecipientUtil.toSignalServiceAddress(context, recipient);
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient);
try {
messageSender.sendNullMessage(address, unidentifiedAccess);
} catch (UntrustedIdentityException e) {
Log.w(TAG, "Unable to send null message.");
}
}
Aggregations