Search in sources :

Example 1 with OutgoingPushMessageList

use of org.whispersystems.signalservice.internal.push.OutgoingPushMessageList in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method sendMessage.

private SendMessageResult sendMessage(SignalServiceAddress recipient, Optional<UnidentifiedAccess> unidentifiedAccess, long timestamp, EnvelopeContent content, boolean online, CancelationSignal cancelationSignal) throws UntrustedIdentityException, IOException {
    enforceMaxContentSize(content);
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < RETRY_COUNT; i++) {
        if (cancelationSignal != null && cancelationSignal.isCanceled()) {
            throw new CancelationException();
        }
        try {
            OutgoingPushMessageList messages = getEncryptedMessages(socket, recipient, unidentifiedAccess, timestamp, content, online);
            if (content.getContent().isPresent() && content.getContent().get().getSyncMessage() != null && content.getContent().get().getSyncMessage().hasSent()) {
                Log.d(TAG, "[sendMessage][" + timestamp + "] Sending a sent sync message to devices: " + messages.getDevices());
            } else if (content.getContent().isPresent() && content.getContent().get().hasSenderKeyDistributionMessage()) {
                Log.d(TAG, "[sendMessage][" + timestamp + "] Sending a SKDM to " + messages.getDestination() + " for devices: " + messages.getDevices());
            }
            if (cancelationSignal != null && cancelationSignal.isCanceled()) {
                throw new CancelationException();
            }
            if (!unidentifiedAccess.isPresent()) {
                try {
                    SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, Optional.absent()).blockingGet()).getResultOrThrow();
                    return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
                } catch (InvalidUnidentifiedAccessHeaderException | UnregisteredUserException | MismatchedDevicesException | StaleDevicesException e) {
                    // Non-technical failures shouldn't be retried with socket
                    throw e;
                } catch (WebSocketUnavailableException e) {
                    Log.i(TAG, "[sendMessage][" + timestamp + "] Pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
                } catch (IOException e) {
                    Log.w(TAG, e);
                    Log.w(TAG, "[sendMessage][" + timestamp + "] Pipe failed, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
                }
            } else if (unidentifiedAccess.isPresent()) {
                try {
                    SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, unidentifiedAccess).blockingGet()).getResultOrThrow();
                    return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
                } catch (InvalidUnidentifiedAccessHeaderException | UnregisteredUserException | MismatchedDevicesException | StaleDevicesException e) {
                    // Non-technical failures shouldn't be retried with socket
                    throw e;
                } catch (WebSocketUnavailableException e) {
                    Log.i(TAG, "[sendMessage][" + timestamp + "] Unidentified pipe unavailable, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
                } catch (IOException e) {
                    Log.w(TAG, e);
                    Log.w(TAG, "[sendMessage][" + timestamp + "] Unidentified pipe failed, falling back...");
                }
            }
            if (cancelationSignal != null && cancelationSignal.isCanceled()) {
                throw new CancelationException();
            }
            SendMessageResponse response = socket.sendMessage(messages, unidentifiedAccess);
            return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || store.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
        } catch (InvalidKeyException ike) {
            Log.w(TAG, ike);
            unidentifiedAccess = Optional.absent();
        } catch (AuthorizationFailedException afe) {
            Log.w(TAG, afe);
            if (unidentifiedAccess.isPresent()) {
                unidentifiedAccess = Optional.absent();
            } else {
                throw afe;
            }
        } catch (MismatchedDevicesException mde) {
            Log.w(TAG, "[sendMessage][" + timestamp + "] Handling mismatched devices. (" + mde.getMessage() + ")");
            handleMismatchedDevices(socket, recipient, mde.getMismatchedDevices());
        } catch (StaleDevicesException ste) {
            Log.w(TAG, "[sendMessage][" + timestamp + "] Handling stale devices. (" + ste.getMessage() + ")");
            handleStaleDevices(recipient, ste.getStaleDevices());
        }
    }
    throw new IOException("Failed to resolve conflicts after " + RETRY_COUNT + " attempts!");
}
Also used : UnregisteredUserException(org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException) GroupStaleDevicesException(org.whispersystems.signalservice.internal.push.exceptions.GroupStaleDevicesException) StaleDevicesException(org.whispersystems.signalservice.internal.push.exceptions.StaleDevicesException) WebSocketUnavailableException(org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException) IOException(java.io.IOException) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) MessagingService(org.whispersystems.signalservice.api.services.MessagingService) OutgoingPushMessageList(org.whispersystems.signalservice.internal.push.OutgoingPushMessageList) SendMessageResponse(org.whispersystems.signalservice.internal.push.SendMessageResponse) AuthorizationFailedException(org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException) GroupMismatchedDevicesException(org.whispersystems.signalservice.internal.push.exceptions.GroupMismatchedDevicesException) MismatchedDevicesException(org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException) InvalidUnidentifiedAccessHeaderException(org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException)

Example 2 with OutgoingPushMessageList

use of org.whispersystems.signalservice.internal.push.OutgoingPushMessageList in project Signal-Android by WhisperSystems.

the class SignalServiceMessageSender method getEncryptedMessages.

private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket, SignalServiceAddress recipient, Optional<UnidentifiedAccess> unidentifiedAccess, long timestamp, EnvelopeContent plaintext, boolean online) throws IOException, InvalidKeyException, UntrustedIdentityException {
    List<OutgoingPushMessage> messages = new LinkedList<>();
    List<Integer> subDevices = store.getSubDeviceSessions(recipient.getIdentifier());
    List<Integer> deviceIds = new ArrayList<>(subDevices.size() + 1);
    deviceIds.add(SignalServiceAddress.DEFAULT_DEVICE_ID);
    deviceIds.addAll(subDevices);
    if (recipient.matches(localAddress)) {
        deviceIds.remove(Integer.valueOf(localDeviceId));
    }
    for (int deviceId : deviceIds) {
        if (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID || store.containsSession(new SignalProtocolAddress(recipient.getIdentifier(), deviceId))) {
            messages.add(getEncryptedMessage(socket, recipient, unidentifiedAccess, deviceId, plaintext));
        }
    }
    return new OutgoingPushMessageList(recipient.getIdentifier(), timestamp, messages, online);
}
Also used : OutgoingPushMessageList(org.whispersystems.signalservice.internal.push.OutgoingPushMessageList) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress) OutgoingPushMessage(org.whispersystems.signalservice.internal.push.OutgoingPushMessage)

Example 3 with OutgoingPushMessageList

use of org.whispersystems.signalservice.internal.push.OutgoingPushMessageList in project libsignal-service-java by signalapp.

the class SignalServiceMessageSender method sendMessage.

private SendMessageResponse sendMessage(SignalServiceAddress recipient, long timestamp, byte[] content, boolean silent) throws UntrustedIdentityException, IOException {
    for (int i = 0; i < 3; i++) {
        try {
            OutgoingPushMessageList messages = getEncryptedMessages(socket, recipient, timestamp, content, silent);
            Optional<SignalServiceMessagePipe> pipe = this.pipe.get();
            if (pipe.isPresent()) {
                try {
                    Log.w(TAG, "Transmitting over pipe...");
                    return pipe.get().send(messages);
                } catch (IOException e) {
                    Log.w(TAG, e);
                    Log.w(TAG, "Falling back to new connection...");
                }
            }
            Log.w(TAG, "Not transmitting over pipe...");
            return socket.sendMessage(messages);
        } catch (MismatchedDevicesException mde) {
            Log.w(TAG, mde);
            handleMismatchedDevices(socket, recipient, mde.getMismatchedDevices());
        } catch (StaleDevicesException ste) {
            Log.w(TAG, ste);
            handleStaleDevices(recipient, ste.getStaleDevices());
        }
    }
    throw new IOException("Failed to resolve conflicts after 3 attempts!");
}
Also used : OutgoingPushMessageList(org.whispersystems.signalservice.internal.push.OutgoingPushMessageList) MismatchedDevicesException(org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException) StaleDevicesException(org.whispersystems.signalservice.internal.push.exceptions.StaleDevicesException) IOException(java.io.IOException)

Example 4 with OutgoingPushMessageList

use of org.whispersystems.signalservice.internal.push.OutgoingPushMessageList in project Signal-Android by WhisperSystems.

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);
}
Also used : Single(io.reactivex.rxjava3.core.Single) SignalWebSocket(org.whispersystems.signalservice.api.SignalWebSocket) Util(org.whispersystems.signalservice.internal.util.Util) SecureRandom(java.security.SecureRandom) UnidentifiedAccess(org.whispersystems.signalservice.api.crypto.UnidentifiedAccess) NotFoundException(org.whispersystems.signalservice.api.push.exceptions.NotFoundException) GroupMismatchedDevicesException(org.whispersystems.signalservice.internal.push.exceptions.GroupMismatchedDevicesException) Locale(java.util.Locale) GroupStaleDevicesException(org.whispersystems.signalservice.internal.push.exceptions.GroupStaleDevicesException) LinkedList(java.util.LinkedList) GroupMismatchedDevices(org.whispersystems.signalservice.internal.push.GroupMismatchedDevices) DefaultResponseMapper(org.whispersystems.signalservice.internal.websocket.DefaultResponseMapper) SendMessageResponse(org.whispersystems.signalservice.internal.push.SendMessageResponse) InvalidUnidentifiedAccessHeaderException(org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException) WebSocketRequestMessage(org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage) ServiceResponse(org.whispersystems.signalservice.internal.ServiceResponse) JsonUtil(org.whispersystems.signalservice.internal.util.JsonUtil) OutgoingPushMessageList(org.whispersystems.signalservice.internal.push.OutgoingPushMessageList) Optional(org.whispersystems.libsignal.util.guava.Optional) UnregisteredUserException(org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException) ByteString(com.google.protobuf.ByteString) List(java.util.List) GroupStaleDevices(org.whispersystems.signalservice.internal.push.GroupStaleDevices) Base64(org.whispersystems.util.Base64) SendGroupMessageResponse(org.whispersystems.signalservice.internal.push.SendGroupMessageResponse) ResponseMapper(org.whispersystems.signalservice.internal.websocket.ResponseMapper) ServiceResponseProcessor(org.whispersystems.signalservice.internal.ServiceResponseProcessor) SendMessageResponse(org.whispersystems.signalservice.internal.push.SendMessageResponse) ServiceResponse(org.whispersystems.signalservice.internal.ServiceResponse) UnregisteredUserException(org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException) WebSocketRequestMessage(org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage) SecureRandom(java.security.SecureRandom) NotFoundException(org.whispersystems.signalservice.api.push.exceptions.NotFoundException) ByteString(com.google.protobuf.ByteString) LinkedList(java.util.LinkedList)

Aggregations

OutgoingPushMessageList (org.whispersystems.signalservice.internal.push.OutgoingPushMessageList)4 IOException (java.io.IOException)2 LinkedList (java.util.LinkedList)2 ContentHint (org.whispersystems.signalservice.api.crypto.ContentHint)2 UnregisteredUserException (org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException)2 SendMessageResponse (org.whispersystems.signalservice.internal.push.SendMessageResponse)2 GroupMismatchedDevicesException (org.whispersystems.signalservice.internal.push.exceptions.GroupMismatchedDevicesException)2 GroupStaleDevicesException (org.whispersystems.signalservice.internal.push.exceptions.GroupStaleDevicesException)2 InvalidUnidentifiedAccessHeaderException (org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException)2 MismatchedDevicesException (org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException)2 StaleDevicesException (org.whispersystems.signalservice.internal.push.exceptions.StaleDevicesException)2 ByteString (com.google.protobuf.ByteString)1 Single (io.reactivex.rxjava3.core.Single)1 SecureRandom (java.security.SecureRandom)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 Locale (java.util.Locale)1 InvalidKeyException (org.whispersystems.libsignal.InvalidKeyException)1 SignalProtocolAddress (org.whispersystems.libsignal.SignalProtocolAddress)1 Optional (org.whispersystems.libsignal.util.guava.Optional)1