use of org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException in project Signal-Android by signalapp.
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.api.push.exceptions.AuthorizationFailedException 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.api.push.exceptions.AuthorizationFailedException 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.api.push.exceptions.AuthorizationFailedException 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.api.push.exceptions.AuthorizationFailedException in project Signal-Android by WhisperSystems.
the class PushServiceSocket method makeStorageRequestResponse.
private Response makeStorageRequestResponse(String authorization, String path, String method, RequestBody body, ResponseCodeHandler responseCodeHandler) throws PushNetworkException, NonSuccessfulResponseCodeException {
ConnectionHolder connectionHolder = getRandom(storageClients, random);
OkHttpClient okHttpClient = connectionHolder.getClient().newBuilder().connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS).readTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS).build();
// Log.d(TAG, "Opening URL: " + connectionHolder.getUrl());
Request.Builder request = new Request.Builder().url(connectionHolder.getUrl() + path);
request.method(method, body);
if (connectionHolder.getHostHeader().isPresent()) {
request.addHeader("Host", connectionHolder.getHostHeader().get());
}
if (authorization != null) {
request.addHeader("Authorization", authorization);
}
Call call = okHttpClient.newCall(request.build());
synchronized (connections) {
connections.add(call);
}
Response response;
try {
response = call.execute();
if (response.isSuccessful() && response.code() != 204) {
return response;
}
} catch (IOException e) {
throw new PushNetworkException(e);
} finally {
synchronized (connections) {
connections.remove(call);
}
}
ResponseBody responseBody = response.body();
try {
responseCodeHandler.handle(response.code(), responseBody);
switch(response.code()) {
case 204:
throw new NoContentException("No content!");
case 401:
case 403:
throw new AuthorizationFailedException(response.code(), "Authorization failed!");
case 404:
throw new NotFoundException("Not found");
case 409:
if (responseBody != null) {
throw new ContactManifestMismatchException(readBodyBytes(responseBody));
} else {
throw new ConflictException();
}
case 429:
throw new RateLimitException("Rate limit exceeded: " + response.code());
case 499:
throw new DeprecatedVersionException();
}
throw new NonSuccessfulResponseCodeException(response.code(), "Response: " + response);
} catch (NonSuccessfulResponseCodeException | PushNetworkException e) {
if (responseBody != null) {
responseBody.close();
}
throw e;
}
}
Aggregations