use of org.whispersystems.libsignal.util.guava.Optional in project Signal-Android by signalapp.
the class MessagingService method send.
public Single<ServiceResponse<SendMessageResponse>> send(OutgoingPushMessageList list, Optional<UnidentifiedAccess> unidentifiedAccess) {
List<String> headers = new LinkedList<String>() {
{
add("content-type:application/json");
}
};
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder().setId(new SecureRandom().nextLong()).setVerb("PUT").setPath(String.format("/v1/messages/%s", list.getDestination())).addAllHeaders(headers).setBody(ByteString.copyFrom(JsonUtil.toJson(list).getBytes())).build();
ResponseMapper<SendMessageResponse> responseMapper = DefaultResponseMapper.extend(SendMessageResponse.class).withResponseMapper((status, body, getHeader, unidentified) -> {
SendMessageResponse sendMessageResponse = Util.isEmpty(body) ? new SendMessageResponse(false, unidentified) : JsonUtil.fromJsonResponse(body, SendMessageResponse.class);
sendMessageResponse.setSentUnidentfied(unidentified);
return ServiceResponse.forResult(sendMessageResponse, status, body);
}).withCustomError(404, (status, body, getHeader) -> new UnregisteredUserException(list.getDestination(), new NotFoundException("not found"))).build();
return signalWebSocket.request(requestMessage, unidentifiedAccess).map(responseMapper::map).onErrorReturn(ServiceResponse::forUnknownError);
}
use of org.whispersystems.libsignal.util.guava.Optional in project Signal-Android by signalapp.
the class SignalServiceCipher method decrypt.
private Plaintext decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolInvalidKeyException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyIdException, ProtocolNoSessionException, SelfSendException, InvalidMessageStructureException {
try {
byte[] paddedMessage;
SignalServiceMetadata metadata;
if (!envelope.hasSourceUuid() && !envelope.isUnidentifiedSender()) {
throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!");
}
if (envelope.isPreKeySignalMessage()) {
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceUuid().get(), envelope.getSourceDevice());
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress));
} else if (envelope.isSignalMessage()) {
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceUuid().get(), envelope.getSourceDevice());
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
} else if (envelope.isPlaintextContent()) {
paddedMessage = new PlaintextContent(ciphertext).getBody();
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
} else if (envelope.isUnidentifiedSender()) {
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orNull(), localDeviceId));
DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, ciphertext, envelope.getServerReceivedTimestamp());
SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164());
Optional<byte[]> groupId = result.getGroupId();
boolean needsReceipt = true;
if (envelope.hasSourceUuid()) {
Log.w(TAG, "[" + envelope.getTimestamp() + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false");
needsReceipt = false;
}
if (result.getCiphertextMessageType() == CiphertextMessage.PREKEY_TYPE) {
signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(new SignalProtocolAddress(result.getSenderUuid(), result.getDeviceId())));
}
paddedMessage = result.getPaddedMessage();
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), needsReceipt, envelope.getServerGuid(), groupId);
} else {
throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
}
PushTransportDetails transportDetails = new PushTransportDetails();
byte[] data = transportDetails.getStrippedPaddingMessageBody(paddedMessage);
return new Plaintext(metadata, data);
} catch (DuplicateMessageException e) {
throw new ProtocolDuplicateMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (LegacyMessageException e) {
throw new ProtocolLegacyMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (InvalidMessageException e) {
throw new ProtocolInvalidMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (InvalidKeyIdException e) {
throw new ProtocolInvalidKeyIdException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (InvalidKeyException e) {
throw new ProtocolInvalidKeyException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (UntrustedIdentityException e) {
throw new ProtocolUntrustedIdentityException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (InvalidVersionException e) {
throw new ProtocolInvalidVersionException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
} catch (NoSessionException e) {
throw new ProtocolNoSessionException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
}
}
use of org.whispersystems.libsignal.util.guava.Optional in project Signal-Android by signalapp.
the class SignalServiceContent method createFromProto.
/**
* Takes internal protobuf serialization format and processes it into a {@link SignalServiceContent}.
*/
public static SignalServiceContent createFromProto(SignalServiceContentProto serviceContentProto) throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException, InvalidMessageStructureException {
SignalServiceMetadata metadata = SignalServiceMetadataProtobufSerializer.fromProtobuf(serviceContentProto.getMetadata());
SignalServiceAddress localAddress = SignalServiceAddressProtobufSerializer.fromProtobuf(serviceContentProto.getLocalAddress());
if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.LEGACYDATAMESSAGE) {
SignalServiceProtos.DataMessage message = serviceContentProto.getLegacyDataMessage();
return new SignalServiceContent(createSignalServiceMessage(metadata, message), Optional.absent(), metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), metadata.isNeedsReceipt(), metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.CONTENT) {
SignalServiceProtos.Content message = serviceContentProto.getContent();
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage = Optional.absent();
if (message.hasSenderKeyDistributionMessage()) {
try {
senderKeyDistributionMessage = Optional.of(new SenderKeyDistributionMessage(message.getSenderKeyDistributionMessage().toByteArray()));
} catch (LegacyMessageException | InvalidMessageException e) {
Log.w(TAG, "Failed to parse SenderKeyDistributionMessage!", e);
}
}
if (message.hasDataMessage()) {
return new SignalServiceContent(createSignalServiceMessage(metadata, message.getDataMessage()), senderKeyDistributionMessage, metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), metadata.isNeedsReceipt(), metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (message.hasSyncMessage() && localAddress.matches(metadata.getSender())) {
return new SignalServiceContent(createSynchronizeMessage(metadata, message.getSyncMessage()), senderKeyDistributionMessage, metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), metadata.isNeedsReceipt(), metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (message.hasCallMessage()) {
return new SignalServiceContent(createCallMessage(message.getCallMessage()), senderKeyDistributionMessage, metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), metadata.isNeedsReceipt(), metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (message.hasReceiptMessage()) {
return new SignalServiceContent(createReceiptMessage(metadata, message.getReceiptMessage()), senderKeyDistributionMessage, metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), metadata.isNeedsReceipt(), metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (message.hasTypingMessage()) {
return new SignalServiceContent(createTypingMessage(metadata, message.getTypingMessage()), senderKeyDistributionMessage, metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), false, metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (message.hasDecryptionErrorMessage()) {
return new SignalServiceContent(createDecryptionErrorMessage(metadata, message.getDecryptionErrorMessage()), senderKeyDistributionMessage, metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), metadata.isNeedsReceipt(), metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
} else if (senderKeyDistributionMessage.isPresent()) {
return new SignalServiceContent(senderKeyDistributionMessage.get(), metadata.getSender(), metadata.getSenderDevice(), metadata.getTimestamp(), metadata.getServerReceivedTimestamp(), metadata.getServerDeliveredTimestamp(), false, metadata.getServerGuid(), metadata.getGroupId(), serviceContentProto);
}
}
return null;
}
use of org.whispersystems.libsignal.util.guava.Optional in project Signal-Android by signalapp.
the class TypingSendJob method onRun.
@Override
public void onRun() throws Exception {
if (!Recipient.self().isRegistered()) {
throw new NotPushRegisteredException();
}
if (!TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
return;
}
Log.d(TAG, "Sending typing " + (typing ? "started" : "stopped") + " for thread " + threadId);
Recipient recipient = SignalDatabase.threads().getRecipientForThreadId(threadId);
if (recipient == null) {
Log.w(TAG, "Tried to send a typing indicator to a non-existent thread.");
return;
}
if (recipient.isBlocked()) {
Log.w(TAG, "Not sending typing indicators to blocked recipients.");
return;
}
if (recipient.isSelf()) {
Log.w(TAG, "Not sending typing indicators to self.");
return;
}
if (recipient.isPushV1Group() || recipient.isMmsGroup()) {
Log.w(TAG, "Not sending typing indicators to unsupported groups.");
return;
}
if (!recipient.isRegistered() || recipient.isForceSmsSelection()) {
Log.w(TAG, "Not sending typing indicators to non-Signal recipients.");
return;
}
List<Recipient> recipients = Collections.singletonList(recipient);
Optional<byte[]> groupId = Optional.absent();
if (recipient.isGroup()) {
recipients = SignalDatabase.groups().getGroupMembers(recipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
groupId = Optional.of(recipient.requireGroupId().getDecodedId());
}
recipients = RecipientUtil.getEligibleForSending(Stream.of(recipients).map(Recipient::resolve).filter(r -> !r.isBlocked()).toList());
SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis(), groupId);
try {
GroupSendUtil.sendTypingMessage(context, recipient.getGroupId().transform(GroupId::requireV2).orNull(), recipients, typingMessage, this::isCanceled);
} catch (CancelationException e) {
Log.w(TAG, "Canceled during send!");
}
}
use of org.whispersystems.libsignal.util.guava.Optional in project Signal-Android by signalapp.
the class MessageContentProcessor method getValidatedQuote.
private Optional<QuoteModel> getValidatedQuote(Optional<SignalServiceDataMessage.Quote> quote) {
if (!quote.isPresent())
return Optional.absent();
if (quote.get().getId() <= 0) {
warn("Received quote without an ID! Ignoring...");
return Optional.absent();
}
if (quote.get().getAuthor() == null) {
warn("Received quote without an author! Ignoring...");
return Optional.absent();
}
RecipientId author = Recipient.externalPush(quote.get().getAuthor()).getId();
MessageRecord message = SignalDatabase.mmsSms().getMessageFor(quote.get().getId(), author);
if (message != null && !message.isRemoteDelete()) {
log("Found matching message record...");
List<Attachment> attachments = new LinkedList<>();
List<Mention> mentions = new LinkedList<>();
if (message.isMms()) {
MmsMessageRecord mmsMessage = (MmsMessageRecord) message;
mentions.addAll(SignalDatabase.mentions().getMentionsForMessage(mmsMessage.getId()));
if (mmsMessage.isViewOnce()) {
attachments.add(new TombstoneAttachment(MediaUtil.VIEW_ONCE, true));
} else {
attachments = mmsMessage.getSlideDeck().asAttachments();
if (attachments.isEmpty()) {
attachments.addAll(Stream.of(mmsMessage.getLinkPreviews()).filter(lp -> lp.getThumbnail().isPresent()).map(lp -> lp.getThumbnail().get()).toList());
}
}
}
return Optional.of(new QuoteModel(quote.get().getId(), author, message.getBody(), false, attachments, mentions));
} else if (message != null) {
warn("Found the target for the quote, but it's flagged as remotely deleted.");
}
warn("Didn't find matching message record...");
return Optional.of(new QuoteModel(quote.get().getId(), author, quote.get().getText(), true, PointerAttachment.forPointers(quote.get().getAttachments()), getMentions(quote.get().getMentions())));
}
Aggregations