Require CDN number match rather than use default CDN

This marks messages as failed if the CDN number does not match a
configured CDN number rather than falling back to the default CDN in
the event the CDN is not recognized.
This commit is contained in:
Ehren Kret 2020-04-14 08:33:09 -07:00 committed by Greyson Parrelli
parent f12a9b9ac7
commit 456bcf3d57
11 changed files with 176 additions and 119 deletions

View File

@ -36,17 +36,17 @@ public class ApplicationDependencies {
private static Application application; private static Application application;
private static Provider provider; private static Provider provider;
private static SignalServiceAccountManager accountManager; private static SignalServiceAccountManager accountManager;
private static SignalServiceMessageSender messageSender; private static SignalServiceMessageSender messageSender;
private static SignalServiceMessageReceiver messageReceiver; private static SignalServiceMessageReceiver messageReceiver;
private static IncomingMessageProcessor incomingMessageProcessor; private static IncomingMessageProcessor incomingMessageProcessor;
private static MessageRetriever messageRetriever; private static MessageRetriever messageRetriever;
private static LiveRecipientCache recipientCache; private static LiveRecipientCache recipientCache;
private static JobManager jobManager; private static JobManager jobManager;
private static FrameRateTracker frameRateTracker; private static FrameRateTracker frameRateTracker;
private static KeyValueStore keyValueStore; private static KeyValueStore keyValueStore;
private static MegaphoneRepository megaphoneRepository; private static MegaphoneRepository megaphoneRepository;
private static GroupsV2Operations groupsV2Operations; private static GroupsV2Operations groupsV2Operations;
public static synchronized void init(@NonNull Application application, @NonNull Provider provider) { public static synchronized void init(@NonNull Application application, @NonNull Provider provider) {
if (ApplicationDependencies.application != null || ApplicationDependencies.provider != null) { if (ApplicationDependencies.application != null || ApplicationDependencies.provider != null) {

View File

@ -30,6 +30,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
@ -168,7 +169,7 @@ public class AttachmentDownloadJob extends BaseJob {
InputStream stream = messageReceiver.retrieveAttachment(pointer, attachmentFile, MAX_ATTACHMENT_SIZE, (total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.NETWORK, total, progress))); InputStream stream = messageReceiver.retrieveAttachment(pointer, attachmentFile, MAX_ATTACHMENT_SIZE, (total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.NETWORK, total, progress)));
database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream); database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream);
} catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException e) { } catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException | MissingConfigurationException e) {
Log.w(TAG, "Experienced exception while trying to download an attachment.", e); Log.w(TAG, "Experienced exception while trying to download an attachment.", e);
markFailed(messageId, attachmentId); markFailed(messageId, attachmentId);
} }

View File

@ -18,6 +18,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver; import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import java.io.File; import java.io.File;
@ -92,7 +93,7 @@ public final class AvatarGroupsV1DownloadJob extends BaseJob {
inputStream.close(); inputStream.close();
} }
} catch (NonSuccessfulResponseCodeException | InvalidMessageException e) { } catch (NonSuccessfulResponseCodeException | InvalidMessageException | MissingConfigurationException e) {
Log.w(TAG, e); Log.w(TAG, e);
} finally { } finally {
if (attachment != null) if (attachment != null)

View File

@ -174,8 +174,8 @@ public class SignalServiceNetworkAccess {
this.censorshipConfiguration = new HashMap<String, SignalServiceConfiguration>() {{ this.censorshipConfiguration = new HashMap<String, SignalServiceConfiguration>() {{
put(COUNTRY_CODE_EGYPT, new SignalServiceConfiguration(new SignalServiceUrl[] {egyptGoogleService, baseGoogleService, baseAndroidService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService}, put(COUNTRY_CODE_EGYPT, new SignalServiceConfiguration(new SignalServiceUrl[] {egyptGoogleService, baseGoogleService, baseAndroidService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {egyptGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn, mailAndroidCdn}, makeSignalCdnUrlMapFor(new SignalCdnUrl[] {egyptGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn, mailAndroidCdn},
new SignalCdnUrl[] {egyptGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2, mailAndroidCdn2}, new SignalCdnUrl[] {egyptGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2, mailAndroidCdn2}),
new SignalContactDiscoveryUrl[] {egyptGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}, new SignalContactDiscoveryUrl[] {egyptGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery},
new SignalKeyBackupServiceUrl[] {egyptGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalKeyBackupServiceUrl[] {egyptGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs},
new SignalStorageUrl[] {egyptGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, new SignalStorageUrl[] {egyptGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage},
@ -184,8 +184,8 @@ public class SignalServiceNetworkAccess {
zkGroupServerPublicParams)); zkGroupServerPublicParams));
put(COUNTRY_CODE_UAE, new SignalServiceConfiguration(new SignalServiceUrl[] {uaeGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService}, put(COUNTRY_CODE_UAE, new SignalServiceConfiguration(new SignalServiceUrl[] {uaeGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {uaeGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn}, makeSignalCdnUrlMapFor(new SignalCdnUrl[] {uaeGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
new SignalCdnUrl[] {uaeGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2}, new SignalCdnUrl[] {uaeGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2}),
new SignalContactDiscoveryUrl[] {uaeGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}, new SignalContactDiscoveryUrl[] {uaeGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery},
new SignalKeyBackupServiceUrl[] {uaeGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalKeyBackupServiceUrl[] {uaeGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs},
new SignalStorageUrl[] {uaeGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, new SignalStorageUrl[] {uaeGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage},
@ -194,8 +194,8 @@ public class SignalServiceNetworkAccess {
zkGroupServerPublicParams)); zkGroupServerPublicParams));
put(COUNTRY_CODE_OMAN, new SignalServiceConfiguration(new SignalServiceUrl[] {omanGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService}, put(COUNTRY_CODE_OMAN, new SignalServiceConfiguration(new SignalServiceUrl[] {omanGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {omanGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn}, makeSignalCdnUrlMapFor(new SignalCdnUrl[] {omanGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
new SignalCdnUrl[] {omanGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2}, new SignalCdnUrl[] {omanGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2}),
new SignalContactDiscoveryUrl[] {omanGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}, new SignalContactDiscoveryUrl[] {omanGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery},
new SignalKeyBackupServiceUrl[] {omanGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalKeyBackupServiceUrl[] {omanGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs},
new SignalStorageUrl[] {omanGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, new SignalStorageUrl[] {omanGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage},
@ -205,8 +205,8 @@ public class SignalServiceNetworkAccess {
put(COUNTRY_CODE_QATAR, new SignalServiceConfiguration(new SignalServiceUrl[] {qatarGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService}, put(COUNTRY_CODE_QATAR, new SignalServiceConfiguration(new SignalServiceUrl[] {qatarGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService},
new SignalCdnUrl[] {qatarGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn}, makeSignalCdnUrlMapFor(new SignalCdnUrl[] {qatarGoogleCdn, baseAndroidCdn, baseGoogleCdn, mapsOneAndroidCdn, mapsTwoAndroidCdn, mailAndroidCdn},
new SignalCdnUrl[] {qatarGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2}, new SignalCdnUrl[] {qatarGoogleCdn2, baseAndroidCdn2, baseGoogleCdn2, mapsOneAndroidCdn2, mapsTwoAndroidCdn2, mailAndroidCdn2}),
new SignalContactDiscoveryUrl[] {qatarGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery}, new SignalContactDiscoveryUrl[] {qatarGoogleDiscovery, baseGoogleDiscovery, baseAndroidDiscovery, mapsOneAndroidDiscovery, mapsTwoAndroidDiscovery, mailAndroidDiscovery},
new SignalKeyBackupServiceUrl[] {qatarGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalKeyBackupServiceUrl[] {qatarGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs},
new SignalStorageUrl[] {qatarGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, new SignalStorageUrl[] {qatarGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage},
@ -216,8 +216,8 @@ public class SignalServiceNetworkAccess {
}}; }};
this.uncensoredConfiguration = new SignalServiceConfiguration(new SignalServiceUrl[] {new SignalServiceUrl(BuildConfig.SIGNAL_URL, new SignalServiceTrustStore(context))}, this.uncensoredConfiguration = new SignalServiceConfiguration(new SignalServiceUrl[] {new SignalServiceUrl(BuildConfig.SIGNAL_URL, new SignalServiceTrustStore(context))},
new SignalCdnUrl[] {new SignalCdnUrl(BuildConfig.SIGNAL_CDN_URL, new SignalServiceTrustStore(context))}, makeSignalCdnUrlMapFor(new SignalCdnUrl[] {new SignalCdnUrl(BuildConfig.SIGNAL_CDN_URL, new SignalServiceTrustStore(context))},
new SignalCdnUrl[] {new SignalCdnUrl(BuildConfig.SIGNAL_CDN2_URL, new SignalServiceTrustStore(context))}, new SignalCdnUrl[] {new SignalCdnUrl(BuildConfig.SIGNAL_CDN2_URL, new SignalServiceTrustStore(context))}),
new SignalContactDiscoveryUrl[] {new SignalContactDiscoveryUrl(BuildConfig.SIGNAL_CONTACT_DISCOVERY_URL, new SignalServiceTrustStore(context))}, new SignalContactDiscoveryUrl[] {new SignalContactDiscoveryUrl(BuildConfig.SIGNAL_CONTACT_DISCOVERY_URL, new SignalServiceTrustStore(context))},
new SignalKeyBackupServiceUrl[] { new SignalKeyBackupServiceUrl(BuildConfig.SIGNAL_KEY_BACKUP_URL, new SignalServiceTrustStore(context)) }, new SignalKeyBackupServiceUrl[] { new SignalKeyBackupServiceUrl(BuildConfig.SIGNAL_KEY_BACKUP_URL, new SignalServiceTrustStore(context)) },
new SignalStorageUrl[] {new SignalStorageUrl(BuildConfig.STORAGE_URL, new SignalServiceTrustStore(context))}, new SignalStorageUrl[] {new SignalStorageUrl(BuildConfig.STORAGE_URL, new SignalServiceTrustStore(context))},
@ -253,4 +253,10 @@ public class SignalServiceNetworkAccess {
return getConfiguration(number) != this.uncensoredConfiguration; return getConfiguration(number) != this.uncensoredConfiguration;
} }
private static Map<Integer, SignalCdnUrl[]> makeSignalCdnUrlMapFor(SignalCdnUrl[] cdn0Urls, SignalCdnUrl[] cdn2Urls) {
Map<Integer, SignalCdnUrl[]> result = new HashMap<>();
result.put(0, cdn0Urls);
result.put(2, cdn2Urls);
return Collections.unmodifiableMap(result);
}
} }

View File

@ -16,7 +16,6 @@ import org.whispersystems.signalservice.FeatureFlags;
import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream; import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream;
import org.whispersystems.signalservice.api.crypto.ProfileCipherInputStream; import org.whispersystems.signalservice.api.crypto.ProfileCipherInputStream;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
@ -25,6 +24,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceStickerManifes
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential; import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.util.CredentialsProvider; import org.whispersystems.signalservice.api.util.CredentialsProvider;
@ -118,8 +118,7 @@ public class SignalServiceMessageReceiver {
* @throws InvalidMessageException * @throws InvalidMessageException
*/ */
public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes) public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes)
throws IOException, InvalidMessageException throws IOException, InvalidMessageException, MissingConfigurationException {
{
return retrieveAttachment(pointer, destination, maxSizeBytes, null); return retrieveAttachment(pointer, destination, maxSizeBytes, null);
} }
@ -174,8 +173,7 @@ public class SignalServiceMessageReceiver {
* @throws InvalidMessageException * @throws InvalidMessageException
*/ */
public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes, ProgressListener listener) public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes, ProgressListener listener)
throws IOException, InvalidMessageException throws IOException, InvalidMessageException, MissingConfigurationException {
{
if (!pointer.getDigest().isPresent()) throw new InvalidMessageException("No attachment digest!"); if (!pointer.getDigest().isPresent()) throw new InvalidMessageException("No attachment digest!");
socket.retrieveAttachment(pointer.getCdnNumber(), pointer.getRemoteId(), destination, maxSizeBytes, listener); socket.retrieveAttachment(pointer.getCdnNumber(), pointer.getRemoteId(), destination, maxSizeBytes, listener);

View File

@ -39,6 +39,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException; import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageProtocolVersionException;
import org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer; import org.whispersystems.signalservice.internal.serialize.SignalServiceAddressProtobufSerializer;
import org.whispersystems.signalservice.internal.serialize.SignalServiceMetadataProtobufSerializer; import org.whispersystems.signalservice.internal.serialize.SignalServiceMetadataProtobufSerializer;
import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceContentProto; import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceContentProto;
@ -268,7 +269,8 @@ public final class SignalServiceContent {
return null; return null;
} }
private static SignalServiceDataMessage createSignalServiceMessage(SignalServiceMetadata metadata, SignalServiceProtos.DataMessage content) private static SignalServiceDataMessage createSignalServiceMessage(SignalServiceMetadata metadata,
SignalServiceProtos.DataMessage content)
throws ProtocolInvalidMessageException, UnsupportedDataMessageException throws ProtocolInvalidMessageException, UnsupportedDataMessageException
{ {
SignalServiceGroup groupInfoV1 = createGroupV1Info(content); SignalServiceGroup groupInfoV1 = createGroupV1Info(content);
@ -292,12 +294,12 @@ public final class SignalServiceContent {
SignalServiceDataMessage.Sticker sticker = createSticker(content); SignalServiceDataMessage.Sticker sticker = createSticker(content);
SignalServiceDataMessage.Reaction reaction = createReaction(content); SignalServiceDataMessage.Reaction reaction = createReaction(content);
if (content.getRequiredProtocolVersion() > SignalServiceProtos.DataMessage.ProtocolVersion.CURRENT.getNumber()) { if (content.getRequiredProtocolVersion() > SignalServiceProtos.DataMessage.ProtocolVersion.CURRENT_VALUE) {
throw new UnsupportedDataMessageException(SignalServiceProtos.DataMessage.ProtocolVersion.CURRENT.getNumber(), throw new UnsupportedDataMessageProtocolVersionException(SignalServiceProtos.DataMessage.ProtocolVersion.CURRENT_VALUE,
content.getRequiredProtocolVersion(), content.getRequiredProtocolVersion(),
metadata.getSender().getIdentifier(), metadata.getSender().getIdentifier(),
metadata.getSenderDevice(), metadata.getSenderDevice(),
groupContext); groupContext);
} }
for (SignalServiceProtos.AttachmentPointer pointer : content.getAttachmentsList()) { for (SignalServiceProtos.AttachmentPointer pointer : content.getAttachmentsList()) {
@ -327,7 +329,8 @@ public final class SignalServiceContent {
reaction); reaction);
} }
private static SignalServiceSyncMessage createSynchronizeMessage(SignalServiceMetadata metadata, SignalServiceProtos.SyncMessage content) private static SignalServiceSyncMessage createSynchronizeMessage(SignalServiceMetadata metadata,
SignalServiceProtos.SyncMessage content)
throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException throws ProtocolInvalidMessageException, ProtocolInvalidKeyException, UnsupportedDataMessageException
{ {
if (content.hasSent()) { if (content.hasSent()) {

View File

@ -0,0 +1,7 @@
package org.whispersystems.signalservice.api.push.exceptions;
public final class MissingConfigurationException extends Exception {
public MissingConfigurationException(String s) {
super(s);
}
}

View File

@ -3,25 +3,24 @@ package org.whispersystems.signalservice.internal.configuration;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List; import java.util.List;
import java.util.Map;
import okhttp3.Dns; import okhttp3.Dns;
import okhttp3.Interceptor; import okhttp3.Interceptor;
public final class SignalServiceConfiguration { public final class SignalServiceConfiguration {
private final SignalServiceUrl[] signalServiceUrls; private final SignalServiceUrl[] signalServiceUrls;
private final SignalCdnUrl[] signalCdnUrls; private final Map<Integer, SignalCdnUrl[]> signalCdnUrlMap;
private final SignalCdnUrl[] signalCdn2Urls; private final SignalContactDiscoveryUrl[] signalContactDiscoveryUrls;
private final SignalContactDiscoveryUrl[] signalContactDiscoveryUrls; private final SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls;
private final SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls; private final SignalStorageUrl[] signalStorageUrls;
private final SignalStorageUrl[] signalStorageUrls; private final List<Interceptor> networkInterceptors;
private final List<Interceptor> networkInterceptors; private final Optional<Dns> dns;
private final Optional<Dns> dns; private final byte[] zkGroupServerPublicParams;
private final byte[] zkGroupServerPublicParams;
public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls, public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls,
SignalCdnUrl[] signalCdnUrls, Map<Integer, SignalCdnUrl[]> signalCdnUrlMap,
SignalCdnUrl[] signalCdn2Urls,
SignalContactDiscoveryUrl[] signalContactDiscoveryUrls, SignalContactDiscoveryUrl[] signalContactDiscoveryUrls,
SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls, SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls,
SignalStorageUrl[] signalStorageUrls, SignalStorageUrl[] signalStorageUrls,
@ -30,8 +29,7 @@ public final class SignalServiceConfiguration {
byte[] zkGroupServerPublicParams) byte[] zkGroupServerPublicParams)
{ {
this.signalServiceUrls = signalServiceUrls; this.signalServiceUrls = signalServiceUrls;
this.signalCdnUrls = signalCdnUrls; this.signalCdnUrlMap = signalCdnUrlMap;
this.signalCdn2Urls = signalCdn2Urls;
this.signalContactDiscoveryUrls = signalContactDiscoveryUrls; this.signalContactDiscoveryUrls = signalContactDiscoveryUrls;
this.signalKeyBackupServiceUrls = signalKeyBackupServiceUrls; this.signalKeyBackupServiceUrls = signalKeyBackupServiceUrls;
this.signalStorageUrls = signalStorageUrls; this.signalStorageUrls = signalStorageUrls;
@ -44,12 +42,8 @@ public final class SignalServiceConfiguration {
return signalServiceUrls; return signalServiceUrls;
} }
public SignalCdnUrl[] getSignalCdnUrls() { public Map<Integer, SignalCdnUrl[]> getSignalCdnUrlMap() {
return signalCdnUrls; return signalCdnUrlMap;
}
public SignalCdnUrl[] getSignalCdn2Urls() {
return signalCdn2Urls;
} }
public SignalContactDiscoveryUrl[] getSignalContactDiscoveryUrls() { public SignalContactDiscoveryUrl[] getSignalContactDiscoveryUrls() {

View File

@ -49,6 +49,7 @@ import org.whispersystems.signalservice.api.push.exceptions.CaptchaRequiredExcep
import org.whispersystems.signalservice.api.push.exceptions.ConflictException; import org.whispersystems.signalservice.api.push.exceptions.ConflictException;
import org.whispersystems.signalservice.api.push.exceptions.ContactManifestMismatchException; import org.whispersystems.signalservice.api.push.exceptions.ContactManifestMismatchException;
import org.whispersystems.signalservice.api.push.exceptions.ExpectationFailedException; import org.whispersystems.signalservice.api.push.exceptions.ExpectationFailedException;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.push.exceptions.NoContentException; import org.whispersystems.signalservice.api.push.exceptions.NoContentException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
@ -62,6 +63,7 @@ import org.whispersystems.signalservice.api.storage.StorageAuthResponse;
import org.whispersystems.signalservice.api.util.CredentialsProvider; import org.whispersystems.signalservice.api.util.CredentialsProvider;
import org.whispersystems.signalservice.api.util.Tls12SocketFactory; import org.whispersystems.signalservice.api.util.Tls12SocketFactory;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl;
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration; import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
import org.whispersystems.signalservice.internal.configuration.SignalUrl; import org.whispersystems.signalservice.internal.configuration.SignalUrl;
import org.whispersystems.signalservice.internal.contacts.entities.DiscoveryRequest; import org.whispersystems.signalservice.internal.contacts.entities.DiscoveryRequest;
@ -98,6 +100,7 @@ import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -191,17 +194,16 @@ public class PushServiceSocket {
private long soTimeoutMillis = TimeUnit.SECONDS.toMillis(30); private long soTimeoutMillis = TimeUnit.SECONDS.toMillis(30);
private final Set<Call> connections = new HashSet<>(); private final Set<Call> connections = new HashSet<>();
private final ServiceConnectionHolder[] serviceClients; private final ServiceConnectionHolder[] serviceClients;
private final ConnectionHolder[] cdnClients; private final Map<Integer, ConnectionHolder[]> cdnClientsMap;
private final ConnectionHolder[] cdn2Clients; private final ConnectionHolder[] contactDiscoveryClients;
private final ConnectionHolder[] contactDiscoveryClients; private final ConnectionHolder[] keyBackupServiceClients;
private final ConnectionHolder[] keyBackupServiceClients; private final ConnectionHolder[] storageClients;
private final ConnectionHolder[] storageClients;
private final CredentialsProvider credentialsProvider; private final CredentialsProvider credentialsProvider;
private final String signalAgent; private final String signalAgent;
private final SecureRandom random; private final SecureRandom random;
private final ClientZkProfileOperations clientZkProfileOperations; private final ClientZkProfileOperations clientZkProfileOperations;
public PushServiceSocket(SignalServiceConfiguration configuration, public PushServiceSocket(SignalServiceConfiguration configuration,
CredentialsProvider credentialsProvider, CredentialsProvider credentialsProvider,
@ -211,8 +213,7 @@ public class PushServiceSocket {
this.credentialsProvider = credentialsProvider; this.credentialsProvider = credentialsProvider;
this.signalAgent = signalAgent; this.signalAgent = signalAgent;
this.serviceClients = createServiceConnectionHolders(configuration.getSignalServiceUrls(), configuration.getNetworkInterceptors(), configuration.getDns()); this.serviceClients = createServiceConnectionHolders(configuration.getSignalServiceUrls(), configuration.getNetworkInterceptors(), configuration.getDns());
this.cdnClients = createConnectionHolders(configuration.getSignalCdnUrls(), configuration.getNetworkInterceptors(), configuration.getDns()); this.cdnClientsMap = createCdnClientsMap(configuration.getSignalCdnUrlMap(), configuration.getNetworkInterceptors(), configuration.getDns());
this.cdn2Clients = createConnectionHolders(configuration.getSignalCdn2Urls(), configuration.getNetworkInterceptors(), configuration.getDns());
this.contactDiscoveryClients = createConnectionHolders(configuration.getSignalContactDiscoveryUrls(), configuration.getNetworkInterceptors(), configuration.getDns()); this.contactDiscoveryClients = createConnectionHolders(configuration.getSignalContactDiscoveryUrls(), configuration.getNetworkInterceptors(), configuration.getDns());
this.keyBackupServiceClients = createConnectionHolders(configuration.getSignalKeyBackupServiceUrls(), configuration.getNetworkInterceptors(), configuration.getDns()); this.keyBackupServiceClients = createConnectionHolders(configuration.getSignalKeyBackupServiceUrls(), configuration.getNetworkInterceptors(), configuration.getDns());
this.storageClients = createConnectionHolders(configuration.getSignalStorageUrls(), configuration.getNetworkInterceptors(), configuration.getDns()); this.storageClients = createConnectionHolders(configuration.getSignalStorageUrls(), configuration.getNetworkInterceptors(), configuration.getDns());
@ -517,8 +518,7 @@ public class PushServiceSocket {
} }
public void retrieveAttachment(int cdnNumber, SignalServiceAttachmentRemoteId cdnPath, File destination, long maxSizeBytes, ProgressListener listener) public void retrieveAttachment(int cdnNumber, SignalServiceAttachmentRemoteId cdnPath, File destination, long maxSizeBytes, ProgressListener listener)
throws NonSuccessfulResponseCodeException, PushNetworkException throws NonSuccessfulResponseCodeException, PushNetworkException, MissingConfigurationException {
{
final String path; final String path;
if (cdnPath.getV2().isPresent()) { if (cdnPath.getV2().isPresent()) {
path = String.format(Locale.US, ATTACHMENT_ID_DOWNLOAD_PATH, cdnPath.getV2().get()); path = String.format(Locale.US, ATTACHMENT_ID_DOWNLOAD_PATH, cdnPath.getV2().get());
@ -529,30 +529,35 @@ public class PushServiceSocket {
} }
public void retrieveSticker(File destination, byte[] packId, int stickerId) public void retrieveSticker(File destination, byte[] packId, int stickerId)
throws NonSuccessfulResponseCodeException, PushNetworkException throws NonSuccessfulResponseCodeException, PushNetworkException, MissingConfigurationException {
{
String hexPackId = Hex.toStringCondensed(packId); String hexPackId = Hex.toStringCondensed(packId);
downloadFromCdn(destination, 0, String.format(Locale.US, STICKER_PATH, hexPackId, stickerId), 1024 * 1024, null); downloadFromCdn(destination, 0, String.format(Locale.US, STICKER_PATH, hexPackId, stickerId), 1024 * 1024, null);
} }
public byte[] retrieveSticker(byte[] packId, int stickerId) public byte[] retrieveSticker(byte[] packId, int stickerId)
throws NonSuccessfulResponseCodeException, PushNetworkException throws NonSuccessfulResponseCodeException, PushNetworkException {
{
String hexPackId = Hex.toStringCondensed(packId); String hexPackId = Hex.toStringCondensed(packId);
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
downloadFromCdn(output, 0, 0, String.format(Locale.US, STICKER_PATH, hexPackId, stickerId), 1024 * 1024, null); try {
downloadFromCdn(output, 0, 0, String.format(Locale.US, STICKER_PATH, hexPackId, stickerId), 1024 * 1024, null);
} catch (MissingConfigurationException e) {
throw new AssertionError(e);
}
return output.toByteArray(); return output.toByteArray();
} }
public byte[] retrieveStickerManifest(byte[] packId) public byte[] retrieveStickerManifest(byte[] packId)
throws NonSuccessfulResponseCodeException, PushNetworkException throws NonSuccessfulResponseCodeException, PushNetworkException {
{
String hexPackId = Hex.toStringCondensed(packId); String hexPackId = Hex.toStringCondensed(packId);
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
downloadFromCdn(output, 0, 0, String.format(STICKER_MANIFEST_PATH, hexPackId), 1024 * 1024, null); try {
downloadFromCdn(output, 0, 0, String.format(STICKER_MANIFEST_PATH, hexPackId), 1024 * 1024, null);
} catch (MissingConfigurationException e) {
throw new AssertionError(e);
}
return output.toByteArray(); return output.toByteArray();
} }
@ -615,9 +620,12 @@ public class PushServiceSocket {
} }
public void retrieveProfileAvatar(String path, File destination, long maxSizeBytes) public void retrieveProfileAvatar(String path, File destination, long maxSizeBytes)
throws NonSuccessfulResponseCodeException, PushNetworkException throws NonSuccessfulResponseCodeException, PushNetworkException {
{ try {
downloadFromCdn(destination, 0, path, maxSizeBytes, null); downloadFromCdn(destination, 0, path, maxSizeBytes, null);
} catch (MissingConfigurationException e) {
throw new AssertionError(e);
}
} }
public void setProfileName(String name) throws NonSuccessfulResponseCodeException, PushNetworkException { public void setProfileName(String name) throws NonSuccessfulResponseCodeException, PushNetworkException {
@ -646,7 +654,7 @@ public class PushServiceSocket {
} }
if (profileAvatar != null) { if (profileAvatar != null) {
uploadToCdn(AVATAR_UPLOAD_PATH, formAttributes.getAcl(), formAttributes.getKey(), uploadToCdn0(AVATAR_UPLOAD_PATH, formAttributes.getAcl(), formAttributes.getKey(),
formAttributes.getPolicy(), formAttributes.getAlgorithm(), formAttributes.getPolicy(), formAttributes.getAlgorithm(),
formAttributes.getCredential(), formAttributes.getDate(), formAttributes.getCredential(), formAttributes.getDate(),
formAttributes.getSignature(), profileAvatar.getData(), formAttributes.getSignature(), profileAvatar.getData(),
@ -682,7 +690,7 @@ public class PushServiceSocket {
throw new NonSuccessfulResponseCodeException("Unable to parse entity"); throw new NonSuccessfulResponseCodeException("Unable to parse entity");
} }
uploadToCdn(AVATAR_UPLOAD_PATH, formAttributes.getAcl(), formAttributes.getKey(), uploadToCdn0(AVATAR_UPLOAD_PATH, formAttributes.getAcl(), formAttributes.getKey(),
formAttributes.getPolicy(), formAttributes.getAlgorithm(), formAttributes.getPolicy(), formAttributes.getAlgorithm(),
formAttributes.getCredential(), formAttributes.getDate(), formAttributes.getCredential(), formAttributes.getDate(),
formAttributes.getSignature(), profileAvatar.getData(), formAttributes.getSignature(), profileAvatar.getData(),
@ -896,7 +904,7 @@ public class PushServiceSocket {
public byte[] uploadGroupV2Avatar(byte[] avatarCipherText, AvatarUploadAttributes uploadAttributes) public byte[] uploadGroupV2Avatar(byte[] avatarCipherText, AvatarUploadAttributes uploadAttributes)
throws IOException throws IOException
{ {
return uploadToCdn(AVATAR_UPLOAD_PATH, uploadAttributes.getAcl(), uploadAttributes.getKey(), return uploadToCdn0(AVATAR_UPLOAD_PATH, uploadAttributes.getAcl(), uploadAttributes.getKey(),
uploadAttributes.getPolicy(), uploadAttributes.getAlgorithm(), uploadAttributes.getPolicy(), uploadAttributes.getAlgorithm(),
uploadAttributes.getCredential(), uploadAttributes.getDate(), uploadAttributes.getCredential(), uploadAttributes.getDate(),
uploadAttributes.getSignature(), uploadAttributes.getSignature(),
@ -910,7 +918,7 @@ public class PushServiceSocket {
throws PushNetworkException, NonSuccessfulResponseCodeException throws PushNetworkException, NonSuccessfulResponseCodeException
{ {
long id = Long.parseLong(uploadAttributes.getAttachmentId()); long id = Long.parseLong(uploadAttributes.getAttachmentId());
byte[] digest = uploadToCdn(ATTACHMENT_UPLOAD_PATH, uploadAttributes.getAcl(), uploadAttributes.getKey(), byte[] digest = uploadToCdn0(ATTACHMENT_UPLOAD_PATH, uploadAttributes.getAcl(), uploadAttributes.getKey(),
uploadAttributes.getPolicy(), uploadAttributes.getAlgorithm(), uploadAttributes.getPolicy(), uploadAttributes.getAlgorithm(),
uploadAttributes.getCredential(), uploadAttributes.getDate(), uploadAttributes.getCredential(), uploadAttributes.getDate(),
uploadAttributes.getSignature(), attachment.getData(), uploadAttributes.getSignature(), attachment.getData(),
@ -933,8 +941,7 @@ public class PushServiceSocket {
} }
private void downloadFromCdn(File destination, int cdnNumber, String path, long maxSizeBytes, ProgressListener listener) private void downloadFromCdn(File destination, int cdnNumber, String path, long maxSizeBytes, ProgressListener listener)
throws PushNetworkException, NonSuccessfulResponseCodeException throws PushNetworkException, NonSuccessfulResponseCodeException, MissingConfigurationException {
{
try (FileOutputStream outputStream = new FileOutputStream(destination, true)) { try (FileOutputStream outputStream = new FileOutputStream(destination, true)) {
downloadFromCdn(outputStream, destination.length(), cdnNumber, path, maxSizeBytes, listener); downloadFromCdn(outputStream, destination.length(), cdnNumber, path, maxSizeBytes, listener);
} catch (IOException e) { } catch (IOException e) {
@ -943,14 +950,17 @@ public class PushServiceSocket {
} }
private void downloadFromCdn(OutputStream outputStream, long offset, int cdnNumber, String path, long maxSizeBytes, ProgressListener listener) private void downloadFromCdn(OutputStream outputStream, long offset, int cdnNumber, String path, long maxSizeBytes, ProgressListener listener)
throws PushNetworkException, NonSuccessfulResponseCodeException throws PushNetworkException, NonSuccessfulResponseCodeException, MissingConfigurationException {
{ ConnectionHolder[] cdnNumberClients = cdnClientsMap.get(cdnNumber);
ConnectionHolder connectionHolder = getRandom(cdnNumber == 2 ? cdn2Clients : cdnClients, random); if (cdnNumberClients == null) {
OkHttpClient okHttpClient = connectionHolder.getClient() throw new MissingConfigurationException("Attempted to download from unsupported CDN number: " + cdnNumber + ", Our configuration supports: " + cdnClientsMap.keySet());
.newBuilder() }
.connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS) ConnectionHolder connectionHolder = getRandom(cdnNumberClients, random);
.readTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS) OkHttpClient okHttpClient = connectionHolder.getClient()
.build(); .newBuilder()
.connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS)
.readTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS)
.build();
Request.Builder request = new Request.Builder().url(connectionHolder.getUrl() + "/" + path).get(); Request.Builder request = new Request.Builder().url(connectionHolder.getUrl() + "/" + path).get();
@ -1012,14 +1022,14 @@ public class PushServiceSocket {
throw new NonSuccessfulResponseCodeException("Response: " + response); throw new NonSuccessfulResponseCodeException("Response: " + response);
} }
private byte[] uploadToCdn(String path, String acl, String key, String policy, String algorithm, private byte[] uploadToCdn0(String path, String acl, String key, String policy, String algorithm,
String credential, String date, String signature, String credential, String date, String signature,
InputStream data, String contentType, long length, InputStream data, String contentType, long length,
OutputStreamFactory outputStreamFactory, ProgressListener progressListener, OutputStreamFactory outputStreamFactory, ProgressListener progressListener,
CancelationSignal cancelationSignal) CancelationSignal cancelationSignal)
throws PushNetworkException, NonSuccessfulResponseCodeException throws PushNetworkException, NonSuccessfulResponseCodeException
{ {
ConnectionHolder connectionHolder = getRandom(cdnClients, random); ConnectionHolder connectionHolder = getRandom(cdnClientsMap.get(0), random);
OkHttpClient okHttpClient = connectionHolder.getClient() OkHttpClient okHttpClient = connectionHolder.getClient()
.newBuilder() .newBuilder()
.connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS) .connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS)
@ -1074,7 +1084,7 @@ public class PushServiceSocket {
} }
private String getResumableUploadUrl(String signedUrl, Map<String, String> headers) throws IOException { private String getResumableUploadUrl(String signedUrl, Map<String, String> headers) throws IOException {
ConnectionHolder connectionHolder = getRandom(cdn2Clients, random); ConnectionHolder connectionHolder = getRandom(cdnClientsMap.get(2), random);
OkHttpClient okHttpClient = connectionHolder.getClient() OkHttpClient okHttpClient = connectionHolder.getClient()
.newBuilder() .newBuilder()
.connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS) .connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS)
@ -1135,7 +1145,7 @@ public class PushServiceSocket {
} }
private byte[] uploadToCdn2(String resumableUrl, InputStream data, String contentType, long length, OutputStreamFactory outputStreamFactory, ProgressListener progressListener, CancelationSignal cancelationSignal) throws IOException { private byte[] uploadToCdn2(String resumableUrl, InputStream data, String contentType, long length, OutputStreamFactory outputStreamFactory, ProgressListener progressListener, CancelationSignal cancelationSignal) throws IOException {
ConnectionHolder connectionHolder = getRandom(cdn2Clients, random); ConnectionHolder connectionHolder = getRandom(cdnClientsMap.get(2), random);
OkHttpClient okHttpClient = connectionHolder.getClient() OkHttpClient okHttpClient = connectionHolder.getClient()
.newBuilder() .newBuilder()
.connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS) .connectTimeout(soTimeoutMillis, TimeUnit.MILLISECONDS)
@ -1531,7 +1541,25 @@ public class PushServiceSocket {
return serviceConnectionHolders.toArray(new ServiceConnectionHolder[0]); return serviceConnectionHolders.toArray(new ServiceConnectionHolder[0]);
} }
private ConnectionHolder[] createConnectionHolders(SignalUrl[] urls, List<Interceptor> interceptors, Optional<Dns> dns) { private static Map<Integer, ConnectionHolder[]> createCdnClientsMap(final Map<Integer, SignalCdnUrl[]> signalCdnUrlMap,
final List<Interceptor> interceptors,
final Optional<Dns> dns) {
validateConfiguration(signalCdnUrlMap);
final Map<Integer, ConnectionHolder[]> result = new HashMap<>();
for (Map.Entry<Integer, SignalCdnUrl[]> entry : signalCdnUrlMap.entrySet()) {
result.put(entry.getKey(),
createConnectionHolders(entry.getValue(), interceptors, dns));
}
return Collections.unmodifiableMap(result);
}
private static void validateConfiguration(Map<Integer, SignalCdnUrl[]> signalCdnUrlMap) {
if (!signalCdnUrlMap.containsKey(0) || !signalCdnUrlMap.containsKey(2)) {
throw new AssertionError("Configuration used to create PushServiceSocket must support CDN 0 and CDN 2");
}
}
private static ConnectionHolder[] createConnectionHolders(SignalUrl[] urls, List<Interceptor> interceptors, Optional<Dns> dns) {
List<ConnectionHolder> connectionHolders = new LinkedList<>(); List<ConnectionHolder> connectionHolders = new LinkedList<>();
for (SignalUrl url : urls) { for (SignalUrl url : urls) {
@ -1541,7 +1569,7 @@ public class PushServiceSocket {
return connectionHolders.toArray(new ConnectionHolder[0]); return connectionHolders.toArray(new ConnectionHolder[0]);
} }
private OkHttpClient createConnectionClient(SignalUrl url, List<Interceptor> interceptors, Optional<Dns> dns) { private static OkHttpClient createConnectionClient(SignalUrl url, List<Interceptor> interceptors, Optional<Dns> dns) {
try { try {
TrustManager[] trustManagers = BlacklistingTrustManager.createFor(url.getTrustStore()); TrustManager[] trustManagers = BlacklistingTrustManager.createFor(url.getTrustStore());

View File

@ -4,33 +4,27 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext; import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
/** /**
* Exception that indicates that the data message has a higher required protocol version than the * Exception that indicates that the data message contains something that is not supported by this
* current client is capable of interpreting. * version of the application. Subclasses provide more specific information about what data was
* found that is not supported.
*/ */
public class UnsupportedDataMessageException extends Exception { public abstract class UnsupportedDataMessageException extends Exception {
private final int requiredVersion;
private final String sender; private final String sender;
private final int senderDevice; private final int senderDevice;
private final Optional<SignalServiceGroupContext> group; private final Optional<SignalServiceGroupContext> group;
public UnsupportedDataMessageException(int currentVersion, protected UnsupportedDataMessageException(String message,
int requiredVersion, String sender,
String sender, int senderDevice,
int senderDevice, Optional<SignalServiceGroupContext> group)
Optional<SignalServiceGroupContext> group)
{ {
super("Required version: " + requiredVersion + ", Our version: " + currentVersion); super(message);
this.requiredVersion = requiredVersion;
this.sender = sender; this.sender = sender;
this.senderDevice = senderDevice; this.senderDevice = senderDevice;
this.group = group; this.group = group;
} }
public int getRequiredVersion() {
return requiredVersion;
}
public String getSender() { public String getSender() {
return sender; return sender;
} }

View File

@ -0,0 +1,25 @@
package org.whispersystems.signalservice.internal.push;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
/**
* Exception that indicates that the data message has a higher required protocol version than the
* current client is capable of interpreting.
*/
public final class UnsupportedDataMessageProtocolVersionException extends UnsupportedDataMessageException {
private final int requiredVersion;
public UnsupportedDataMessageProtocolVersionException(int currentVersion,
int requiredVersion,
String sender,
int senderDevice,
Optional<SignalServiceGroupContext> group) {
super("Required version: " + requiredVersion + ", Our version: " + currentVersion, sender, senderDevice, group);
this.requiredVersion = requiredVersion;
}
public int getRequiredVersion() {
return requiredVersion;
}
}