use of org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException in project libsignal-service-java by signalapp.
the class PushServiceSocket method makeServiceRequest.
private String makeServiceRequest(String urlFragment, String method, String body) throws NonSuccessfulResponseCodeException, PushNetworkException {
Response response = getServiceConnection(urlFragment, method, body);
int responseCode;
String responseMessage;
String responseBody;
try {
responseCode = response.code();
responseMessage = response.message();
responseBody = response.body().string();
} catch (IOException ioe) {
throw new PushNetworkException(ioe);
}
switch(responseCode) {
case 413:
throw new RateLimitException("Rate limit exceeded: " + responseCode);
case 401:
case 403:
throw new AuthorizationFailedException("Authorization failed!");
case 404:
throw new NotFoundException("Not found");
case 409:
MismatchedDevices mismatchedDevices;
try {
mismatchedDevices = JsonUtil.fromJson(responseBody, MismatchedDevices.class);
} catch (JsonProcessingException e) {
Log.w(TAG, e);
throw new NonSuccessfulResponseCodeException("Bad response: " + responseCode + " " + responseMessage);
} catch (IOException e) {
throw new PushNetworkException(e);
}
throw new MismatchedDevicesException(mismatchedDevices);
case 410:
StaleDevices staleDevices;
try {
staleDevices = JsonUtil.fromJson(responseBody, StaleDevices.class);
} catch (JsonProcessingException e) {
throw new NonSuccessfulResponseCodeException("Bad response: " + responseCode + " " + responseMessage);
} catch (IOException e) {
throw new PushNetworkException(e);
}
throw new StaleDevicesException(staleDevices);
case 411:
DeviceLimit deviceLimit;
try {
deviceLimit = JsonUtil.fromJson(responseBody, DeviceLimit.class);
} catch (JsonProcessingException e) {
throw new NonSuccessfulResponseCodeException("Bad response: " + responseCode + " " + responseMessage);
} catch (IOException e) {
throw new PushNetworkException(e);
}
throw new DeviceLimitExceededException(deviceLimit);
case 417:
throw new ExpectationFailedException();
case 423:
RegistrationLockFailure accountLockFailure;
try {
accountLockFailure = JsonUtil.fromJson(responseBody, RegistrationLockFailure.class);
} catch (JsonProcessingException e) {
Log.w(TAG, e);
throw new NonSuccessfulResponseCodeException("Bad response: " + responseCode + " " + responseMessage);
} catch (IOException e) {
throw new PushNetworkException(e);
}
throw new LockedException(accountLockFailure.length, accountLockFailure.timeRemaining);
}
if (responseCode != 200 && responseCode != 204) {
throw new NonSuccessfulResponseCodeException("Bad response: " + responseCode + " " + responseMessage);
}
return responseBody;
}
use of org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException in project Signal-Android by WhisperSystems.
the class PushServiceSocket method validateServiceResponse.
private Response validateServiceResponse(Response response) throws NonSuccessfulResponseCodeException, PushNetworkException, MalformedResponseException {
int responseCode = response.code();
String responseMessage = response.message();
switch(responseCode) {
case 413:
throw new RateLimitException("Rate limit exceeded: " + responseCode);
case 401:
case 403:
throw new AuthorizationFailedException(responseCode, "Authorization failed!");
case 404:
throw new NotFoundException("Not found");
case 409:
MismatchedDevices mismatchedDevices = readResponseJson(response, MismatchedDevices.class);
throw new MismatchedDevicesException(mismatchedDevices);
case 410:
StaleDevices staleDevices = readResponseJson(response, StaleDevices.class);
throw new StaleDevicesException(staleDevices);
case 411:
DeviceLimit deviceLimit = readResponseJson(response, DeviceLimit.class);
throw new DeviceLimitExceededException(deviceLimit);
case 417:
throw new ExpectationFailedException();
case 423:
RegistrationLockFailure accountLockFailure = readResponseJson(response, RegistrationLockFailure.class);
AuthCredentials credentials = accountLockFailure.backupCredentials;
String basicStorageCredentials = credentials != null ? credentials.asBasic() : null;
throw new LockedException(accountLockFailure.length, accountLockFailure.timeRemaining, basicStorageCredentials);
case 428:
ProofRequiredResponse proofRequiredResponse = readResponseJson(response, ProofRequiredResponse.class);
String retryAfterRaw = response.header("Retry-After");
long retryAfter = Util.parseInt(retryAfterRaw, -1);
throw new ProofRequiredException(proofRequiredResponse, retryAfter);
case 499:
throw new DeprecatedVersionException();
case 508:
throw new ServerRejectedException();
}
if (responseCode != 200 && responseCode != 202 && responseCode != 204) {
throw new NonSuccessfulResponseCodeException(responseCode, "Bad response: " + responseCode + " " + responseMessage);
}
return response;
}
use of org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException in project Signal-Android by WhisperSystems.
the class DefaultErrorMapper method parseError.
@Override
public Throwable parseError(int status, String body, Function<String, String> getHeader) {
if (customErrorMappers.containsKey(status)) {
try {
return customErrorMappers.get(status).parseError(status, body, getHeader);
} catch (MalformedResponseException e) {
return e;
}
}
switch(status) {
case 401:
case 403:
return new AuthorizationFailedException(status, "Authorization failed!");
case 402:
return new CaptchaRequiredException();
case 404:
return new NotFoundException("Not found");
case 409:
try {
return new MismatchedDevicesException(JsonUtil.fromJsonResponse(body, MismatchedDevices.class));
} catch (MalformedResponseException e) {
return e;
}
case 410:
try {
return new StaleDevicesException(JsonUtil.fromJsonResponse(body, StaleDevices.class));
} catch (MalformedResponseException e) {
return e;
}
case 411:
try {
return new DeviceLimitExceededException(JsonUtil.fromJsonResponse(body, DeviceLimit.class));
} catch (MalformedResponseException e) {
return e;
}
case 413:
return new RateLimitException("Rate limit exceeded: " + status);
case 417:
return new ExpectationFailedException();
case 423:
PushServiceSocket.RegistrationLockFailure accountLockFailure;
try {
accountLockFailure = JsonUtil.fromJsonResponse(body, PushServiceSocket.RegistrationLockFailure.class);
} catch (MalformedResponseException e) {
return e;
}
AuthCredentials credentials = accountLockFailure.backupCredentials;
String basicStorageCredentials = credentials != null ? credentials.asBasic() : null;
return new LockedException(accountLockFailure.length, accountLockFailure.timeRemaining, basicStorageCredentials);
case 428:
ProofRequiredResponse proofRequiredResponse;
try {
proofRequiredResponse = JsonUtil.fromJsonResponse(body, ProofRequiredResponse.class);
} catch (MalformedResponseException e) {
return e;
}
String retryAfterRaw = getHeader.apply("Retry-After");
long retryAfter = Util.parseInt(retryAfterRaw, -1);
return new ProofRequiredException(proofRequiredResponse, retryAfter);
case 499:
return new DeprecatedVersionException();
case 508:
return new ServerRejectedException();
}
if (status != 200 && status != 202 && status != 204) {
return new NonSuccessfulResponseCodeException(status, "Bad response: " + status);
}
return null;
}
use of org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException 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!");
}
use of org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException 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!");
}
Aggregations