kopia lustrzana https://github.com/ryukoposting/Signal-Android
Always use sealed sender when sending stories.
rodzic
a9a64a3f60
commit
3895578d51
|
@ -77,7 +77,7 @@ class AdvancedPrivacySettingsViewModel(
|
|||
fun setCensorshipCircumventionEnabled(enabled: Boolean) {
|
||||
SignalStore.settings().setCensorshipCircumventionEnabled(enabled)
|
||||
SignalStore.misc().isServiceReachableWithoutCircumvention = false
|
||||
ApplicationDependencies.resetNetworkConnectionsAfterProxyChange()
|
||||
ApplicationDependencies.resetAllNetworkConnections()
|
||||
refresh()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ import org.signal.libsignal.protocol.ecc.Curve;
|
|||
import org.signal.libsignal.protocol.ecc.ECPublicKey;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
import org.thoughtcrime.securesms.keyvalue.CertificateType;
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
|
@ -68,8 +70,8 @@ public class UnidentifiedAccessUtil {
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
public static Map<RecipientId, Optional<UnidentifiedAccessPair>> getAccessMapFor(@NonNull Context context, @NonNull List<Recipient> recipients) {
|
||||
List<Optional<UnidentifiedAccessPair>> accessList = getAccessFor(context, recipients, true);
|
||||
public static Map<RecipientId, Optional<UnidentifiedAccessPair>> getAccessMapFor(@NonNull Context context, @NonNull List<Recipient> recipients, boolean isForStory) {
|
||||
List<Optional<UnidentifiedAccessPair>> accessList = getAccessFor(context, recipients, true, isForStory);
|
||||
|
||||
Iterator<Recipient> recipientIterator = recipients.iterator();
|
||||
Iterator<Optional<UnidentifiedAccessPair>> accessIterator = accessList.iterator();
|
||||
|
@ -82,9 +84,14 @@ public class UnidentifiedAccessUtil {
|
|||
|
||||
return accessMap;
|
||||
}
|
||||
|
||||
|
||||
@WorkerThread
|
||||
public static List<Optional<UnidentifiedAccessPair>> getAccessFor(@NonNull Context context, @NonNull List<Recipient> recipients, boolean log) {
|
||||
return getAccessFor(context, recipients, false, log);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static List<Optional<UnidentifiedAccessPair>> getAccessFor(@NonNull Context context, @NonNull List<Recipient> recipients, boolean isForStory, boolean log) {
|
||||
byte[] ourUnidentifiedAccessKey = UnidentifiedAccess.deriveAccessKeyFrom(ProfileKeyUtil.getSelfProfileKey());
|
||||
|
||||
if (TextSecurePreferences.isUniversalUnidentifiedAccess(context)) {
|
||||
|
@ -96,7 +103,7 @@ public class UnidentifiedAccessUtil {
|
|||
Map<CertificateType, Integer> typeCounts = new HashMap<>();
|
||||
|
||||
for (Recipient recipient : recipients) {
|
||||
byte[] theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient);
|
||||
byte[] theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient, isForStory);
|
||||
CertificateType certificateType = getUnidentifiedAccessCertificateType(recipient);
|
||||
byte[] ourUnidentifiedAccessCertificate = SignalStore.certificateValues().getUnidentifiedAccessCertificate(certificateType);
|
||||
|
||||
|
@ -168,28 +175,40 @@ public class UnidentifiedAccessUtil {
|
|||
.getUnidentifiedAccessCertificate(getUnidentifiedAccessCertificateType(recipient));
|
||||
}
|
||||
|
||||
private static @Nullable byte[] getTargetUnidentifiedAccessKey(@NonNull Recipient recipient) {
|
||||
private static @Nullable byte[] getTargetUnidentifiedAccessKey(@NonNull Recipient recipient, boolean isForStory) {
|
||||
ProfileKey theirProfileKey = ProfileKeyUtil.profileKeyOrNull(recipient.resolve().getProfileKey());
|
||||
|
||||
byte[] accessKey;
|
||||
|
||||
switch (recipient.resolve().getUnidentifiedAccessMode()) {
|
||||
case UNKNOWN:
|
||||
if (theirProfileKey == null) {
|
||||
return UNRESTRICTED_KEY;
|
||||
accessKey = UNRESTRICTED_KEY;
|
||||
} else {
|
||||
return UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
|
||||
accessKey = UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
|
||||
}
|
||||
break;
|
||||
case DISABLED:
|
||||
return null;
|
||||
accessKey = null;
|
||||
break;
|
||||
case ENABLED:
|
||||
if (theirProfileKey == null) {
|
||||
return null;
|
||||
accessKey = null;
|
||||
} else {
|
||||
return UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
|
||||
accessKey = UnidentifiedAccess.deriveAccessKeyFrom(theirProfileKey);
|
||||
}
|
||||
break;
|
||||
case UNRESTRICTED:
|
||||
return UNRESTRICTED_KEY;
|
||||
accessKey = UNRESTRICTED_KEY;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unknown mode: " + recipient.getUnidentifiedAccessMode().getMode());
|
||||
}
|
||||
|
||||
if (accessKey == null && isForStory) {
|
||||
accessKey = UNRESTRICTED_KEY;
|
||||
}
|
||||
|
||||
return accessKey;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,7 +258,7 @@ public class ApplicationDependencies {
|
|||
}
|
||||
}
|
||||
|
||||
public static void resetNetworkConnectionsAfterProxyChange() {
|
||||
public static void resetAllNetworkConnections() {
|
||||
synchronized (LOCK) {
|
||||
closeConnections();
|
||||
if (signalWebSocket != null) {
|
||||
|
|
|
@ -63,6 +63,7 @@ import org.thoughtcrime.securesms.service.PendingRetryReceiptManager;
|
|||
import org.thoughtcrime.securesms.service.TrimThreadsByDateManager;
|
||||
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager;
|
||||
import org.thoughtcrime.securesms.shakereport.ShakeToReport;
|
||||
import org.thoughtcrime.securesms.stories.Stories;
|
||||
import org.thoughtcrime.securesms.util.AlarmSleepTimer;
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||
import org.thoughtcrime.securesms.util.ByteUnit;
|
||||
|
@ -398,7 +399,8 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
|
|||
signalServiceConfigurationSupplier.get(),
|
||||
Optional.of(new DynamicCredentialsProvider()),
|
||||
BuildConfig.SIGNAL_AGENT,
|
||||
healthMonitor);
|
||||
healthMonitor,
|
||||
Stories.isFeatureEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -407,7 +409,8 @@ public class ApplicationDependencyProvider implements ApplicationDependencies.Pr
|
|||
signalServiceConfigurationSupplier.get(),
|
||||
Optional.empty(),
|
||||
BuildConfig.SIGNAL_AGENT,
|
||||
healthMonitor);
|
||||
healthMonitor,
|
||||
Stories.isFeatureEnabled());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.jobmanager.Data
|
|||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState
|
||||
import org.whispersystems.signalservice.internal.util.StaticCredentialsProvider
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection
|
||||
|
@ -78,7 +79,8 @@ class CheckServiceReachabilityJob private constructor(params: Parameters) : Base
|
|||
),
|
||||
BuildConfig.SIGNAL_AGENT,
|
||||
null,
|
||||
""
|
||||
"",
|
||||
Stories.isFeatureEnabled()
|
||||
)
|
||||
|
||||
try {
|
||||
|
|
|
@ -102,6 +102,11 @@ public final class PushDecryptMessageJob extends BaseJob {
|
|||
List<Job> jobs = new LinkedList<>();
|
||||
DecryptionResult result = MessageDecryptionUtil.decrypt(context, envelope);
|
||||
|
||||
if (result.getState() == MessageState.DECRYPTED_OK && envelope.isStory() && !isStoryMessage(result)) {
|
||||
Log.w(TAG, "Envelope was flagged as a story, but it did not have any story-related content! Dropping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.getContent() != null) {
|
||||
if (result.getContent().getSenderKeyDistributionMessage().isPresent()) {
|
||||
handleSenderKeyDistributionMessage(result.getContent().getSender(), result.getContent().getSenderDevice(), result.getContent().getSenderKeyDistributionMessage().get());
|
||||
|
@ -172,6 +177,25 @@ public final class PushDecryptMessageJob extends BaseJob {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isStoryMessage(@NonNull DecryptionResult result) {
|
||||
if (result.getContent() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result.getContent().getStoryMessage().isPresent()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result.getContent().getDataMessage().isPresent() &&
|
||||
result.getContent().getDataMessage().get().getStoryContext().isPresent() &&
|
||||
result.getContent().getDataMessage().get().getGroupContext().isPresent())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean needsMigration() {
|
||||
return TextSecurePreferences.getNeedsSqlCipherMigration(context);
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ public final class SenderKeyDistributionSendJob extends BaseJob {
|
|||
SenderKeyDistributionMessage message = messageSender.getOrCreateNewGroupSession(distributionId);
|
||||
List<Optional<UnidentifiedAccessPair>> access = UnidentifiedAccessUtil.getAccessFor(context, Collections.singletonList(targetRecipient));
|
||||
|
||||
SendMessageResult result = messageSender.sendSenderKeyDistributionMessage(distributionId, address, access, message, Optional.ofNullable(groupId).map(GroupId::getDecodedId), false).get(0);
|
||||
SendMessageResult result = messageSender.sendSenderKeyDistributionMessage(distributionId, address, access, message, Optional.ofNullable(groupId).map(GroupId::getDecodedId), false, false).get(0);
|
||||
|
||||
if (result.isSuccess()) {
|
||||
List<SignalProtocolAddress> addresses = result.getSuccess()
|
||||
|
|
|
@ -94,7 +94,7 @@ public final class GroupSendUtil {
|
|||
boolean urgent)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, DataSendOperation.resendable(message, contentHint, messageId, urgent), null);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, false, DataSendOperation.resendable(message, contentHint, messageId, urgent), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +116,7 @@ public final class GroupSendUtil {
|
|||
boolean urgent)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, isRecipientUpdate, DataSendOperation.unresendable(message, contentHint, urgent), null);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, isRecipientUpdate, false, DataSendOperation.unresendable(message, contentHint, urgent), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +133,7 @@ public final class GroupSendUtil {
|
|||
@Nullable CancelationSignal cancelationSignal)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, new TypingSendOperation(message), cancelationSignal);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, false, new TypingSendOperation(message), cancelationSignal);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,11 +149,11 @@ public final class GroupSendUtil {
|
|||
@NonNull SignalServiceCallMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, new CallSendOperation(message), null);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, false, new CallSendOperation(message), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles all of the logic of sending a story to a group. Will do sender key sends and legacy 1:1 sends as-needed, and give you back a list of
|
||||
* Handles all of the logic of sending a story to a distribution list. Will do sender key sends and legacy 1:1 sends as-needed, and give you back a list of
|
||||
* {@link SendMessageResult}s just like we're used to.
|
||||
*
|
||||
* @param isRecipientUpdate True if you've already sent this message to some recipients in the past, otherwise false.
|
||||
|
@ -175,6 +175,7 @@ public final class GroupSendUtil {
|
|||
messageId,
|
||||
allTargets,
|
||||
isRecipientUpdate,
|
||||
true,
|
||||
new StorySendOperation(messageId, null, sentTimestamp, message, manifest),
|
||||
null);
|
||||
}
|
||||
|
@ -201,6 +202,7 @@ public final class GroupSendUtil {
|
|||
messageId,
|
||||
allTargets,
|
||||
isRecipientUpdate,
|
||||
true,
|
||||
new StorySendOperation(messageId, groupId, sentTimestamp, message, Collections.emptySet()),
|
||||
null);
|
||||
}
|
||||
|
@ -219,6 +221,7 @@ public final class GroupSendUtil {
|
|||
@Nullable MessageId relatedMessageId,
|
||||
@NonNull List<Recipient> allTargets,
|
||||
boolean isRecipientUpdate,
|
||||
boolean isStorySend,
|
||||
@NonNull SendOperation sendOperation,
|
||||
@Nullable CancelationSignal cancelationSignal)
|
||||
throws IOException, UntrustedIdentityException
|
||||
|
@ -228,7 +231,7 @@ public final class GroupSendUtil {
|
|||
Set<Recipient> unregisteredTargets = allTargets.stream().filter(Recipient::isUnregistered).collect(Collectors.toSet());
|
||||
List<Recipient> registeredTargets = allTargets.stream().filter(r -> !unregisteredTargets.contains(r)).collect(Collectors.toList());
|
||||
|
||||
RecipientData recipients = new RecipientData(context, registeredTargets);
|
||||
RecipientData recipients = new RecipientData(context, registeredTargets, isStorySend);
|
||||
Optional<GroupRecord> groupRecord = groupId != null ? SignalDatabase.groups().getGroup(groupId) : Optional.empty();
|
||||
|
||||
List<Recipient> senderKeyTargets = new LinkedList<>();
|
||||
|
@ -257,6 +260,11 @@ public final class GroupSendUtil {
|
|||
Log.i(TAG, "No DistributionId. Using legacy.");
|
||||
legacyTargets.addAll(senderKeyTargets);
|
||||
senderKeyTargets.clear();
|
||||
} else if (isStorySend) {
|
||||
Log.i(TAG, "Sending a story. Using sender key for all " + allTargets.size() + " recipients.");
|
||||
senderKeyTargets.clear();
|
||||
senderKeyTargets.addAll(registeredTargets);
|
||||
legacyTargets.clear();
|
||||
} else if (SignalStore.internalValues().removeSenderKeyMinimum()) {
|
||||
Log.i(TAG, "Sender key minimum removed. Using for " + senderKeyTargets.size() + " recipients.");
|
||||
} else if (senderKeyTargets.size() < 2) {
|
||||
|
@ -681,7 +689,7 @@ public final class GroupSendUtil {
|
|||
@Nullable CancelationSignal cancelationSignal)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return messageSender.sendStory(targets, access, isRecipientUpdate, message, getSentTimestamp(), manifest);
|
||||
throw new UnsupportedOperationException("Stories can only be send via sender key!");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -767,8 +775,8 @@ public final class GroupSendUtil {
|
|||
private final Map<RecipientId, SignalServiceAddress> addressById;
|
||||
private final RecipientAccessList accessList;
|
||||
|
||||
RecipientData(@NonNull Context context, @NonNull List<Recipient> recipients) throws IOException {
|
||||
this.accessById = UnidentifiedAccessUtil.getAccessMapFor(context, recipients);
|
||||
RecipientData(@NonNull Context context, @NonNull List<Recipient> recipients, boolean isForStory) throws IOException {
|
||||
this.accessById = UnidentifiedAccessUtil.getAccessMapFor(context, recipients, isForStory);
|
||||
this.addressById = mapAddresses(context, recipients);
|
||||
this.accessList = new RecipientAccessList(recipients);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.thoughtcrime.securesms.jobmanager.JobTracker;
|
|||
import org.thoughtcrime.securesms.jobs.MarkerJob;
|
||||
import org.thoughtcrime.securesms.jobs.PushDecryptMessageJob;
|
||||
import org.thoughtcrime.securesms.jobs.PushProcessMessageJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.stories.Stories;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -82,7 +84,7 @@ public class RestStrategy extends MessageRetrievalStrategy {
|
|||
|
||||
receiver.setSoTimeoutMillis(timeout);
|
||||
|
||||
receiver.retrieveMessages(envelope -> {
|
||||
receiver.retrieveMessages(Stories.isFeatureEnabled(), envelope -> {
|
||||
Log.i(TAG, "Retrieved an envelope." + timeSuffix(startTime));
|
||||
String jobId = processor.processEnvelope(envelope);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import io.reactivex.rxjava3.core.Single
|
|||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
@ -25,6 +26,7 @@ class StoriesPrivacySettingsRepository {
|
|||
return Completable.fromAction {
|
||||
SignalStore.storyValues().isFeatureDisabled = !isEnabled
|
||||
Stories.onStorySettingsChanged(Recipient.self().id)
|
||||
ApplicationDependencies.resetAllNetworkConnections()
|
||||
|
||||
SignalDatabase.mms.getAllOutgoingStories(false, -1).use { reader ->
|
||||
reader.map { record -> record.id }
|
||||
|
|
|
@ -249,7 +249,10 @@ public final class FeatureFlags {
|
|||
*/
|
||||
private static final Map<String, OnFlagChange> FLAG_CHANGE_LISTENERS = new HashMap<String, OnFlagChange>() {{
|
||||
put(MESSAGE_PROCESSOR_ALARM_INTERVAL, change -> MessageProcessReceiver.startOrUpdateAlarm(ApplicationDependencies.getApplication()));
|
||||
put(STORIES, change -> ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob()).then(new RefreshOwnProfileJob()).enqueue());
|
||||
put(STORIES, change -> {
|
||||
ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob()).then(new RefreshOwnProfileJob()).enqueue();
|
||||
ApplicationDependencies.resetAllNetworkConnections();
|
||||
});
|
||||
put(GIFT_BADGE_RECEIVE_SUPPORT, change -> ApplicationDependencies.getJobManager().startChain(new RefreshAttributesJob()).then(new RefreshOwnProfileJob()).enqueue());
|
||||
}};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public final class SignalProxyUtil {
|
|||
public static void enableProxy(@NonNull SignalProxy proxy) {
|
||||
SignalStore.proxy().enableProxy(proxy);
|
||||
Conscrypt.setUseEngineSocketByDefault(true);
|
||||
ApplicationDependencies.resetNetworkConnectionsAfterProxyChange();
|
||||
ApplicationDependencies.resetAllNetworkConnections();
|
||||
startListeningToWebsocket();
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ public final class SignalProxyUtil {
|
|||
public static void disableProxy() {
|
||||
SignalStore.proxy().disableProxy();
|
||||
Conscrypt.setUseEngineSocketByDefault(false);
|
||||
ApplicationDependencies.resetNetworkConnectionsAfterProxyChange();
|
||||
ApplicationDependencies.resetAllNetworkConnections();
|
||||
startListeningToWebsocket();
|
||||
}
|
||||
|
||||
|
|
|
@ -195,15 +195,11 @@ public class SignalServiceMessageReceiver {
|
|||
return new SignalServiceStickerManifest(pack.getTitle(), pack.getAuthor(), cover, stickers);
|
||||
}
|
||||
|
||||
public List<SignalServiceEnvelope> retrieveMessages() throws IOException {
|
||||
return retrieveMessages(new NullMessageReceivedCallback());
|
||||
}
|
||||
|
||||
public List<SignalServiceEnvelope> retrieveMessages(MessageReceivedCallback callback)
|
||||
public List<SignalServiceEnvelope> retrieveMessages(boolean allowStories, MessageReceivedCallback callback)
|
||||
throws IOException
|
||||
{
|
||||
List<SignalServiceEnvelope> results = new LinkedList<>();
|
||||
SignalServiceMessagesResult messageResult = socket.getMessages();
|
||||
SignalServiceMessagesResult messageResult = socket.getMessages(allowStories);
|
||||
|
||||
for (SignalServiceEnvelopeEntity entity : messageResult.getEnvelopes()) {
|
||||
SignalServiceEnvelope envelope;
|
||||
|
|
|
@ -221,7 +221,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
return sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getWhen(), envelopeContent, false, null, false);
|
||||
return sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getWhen(), envelopeContent, false, null, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,7 +237,7 @@ public class SignalServiceMessageSender {
|
|||
PlaintextContent content = new PlaintextContent(errorMessage);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.plaintext(content, groupId);
|
||||
|
||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, false);
|
||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,7 +252,7 @@ public class SignalServiceMessageSender {
|
|||
Content content = createTypingContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), envelopeContent, true, null, cancelationSignal, false);
|
||||
sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), envelopeContent, true, null, cancelationSignal, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -265,31 +265,12 @@ public class SignalServiceMessageSender {
|
|||
throws IOException, UntrustedIdentityException, InvalidKeyException, NoSessionException, InvalidRegistrationIdException
|
||||
{
|
||||
Content content = createTypingContent(message);
|
||||
sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, ContentHint.IMPLICIT, message.getGroupId(), true, SenderKeyGroupEvents.EMPTY, false);
|
||||
}
|
||||
|
||||
public List<SendMessageResult> sendStory(List<SignalServiceAddress> recipients,
|
||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
||||
boolean isRecipientUpdate,
|
||||
SignalServiceStoryMessage message,
|
||||
long timestamp,
|
||||
Set<SignalServiceStoryMessageRecipient> manifest)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
Content content = createStoryContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
List<SendMessageResult> sendMessageResults = sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, null, false);
|
||||
|
||||
if (aciStore.isMultiDevice()) {
|
||||
SignalServiceSyncMessage syncMessage = createSelfSendSyncMessageForStory(message, timestamp, isRecipientUpdate, manifest);
|
||||
sendSyncMessage(syncMessage, Optional.empty());
|
||||
}
|
||||
|
||||
return sendMessageResults;
|
||||
sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, ContentHint.IMPLICIT, message.getGroupId(), true, SenderKeyGroupEvents.EMPTY, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a story using sender key.
|
||||
* Send a story using sender key. Note: This is not just for group stories -- it's for any story. Just following the naming convention of making sender key
|
||||
* method named "sendGroup*"
|
||||
*/
|
||||
public List<SendMessageResult> sendGroupStory(DistributionId distributionId,
|
||||
Optional<byte[]> groupId,
|
||||
|
@ -302,7 +283,7 @@ public class SignalServiceMessageSender {
|
|||
throws IOException, UntrustedIdentityException, InvalidKeyException, NoSessionException, InvalidRegistrationIdException
|
||||
{
|
||||
Content content = createStoryContent(message);
|
||||
List<SendMessageResult> sendMessageResults = sendGroupMessage(distributionId, recipients, unidentifiedAccess, timestamp, content, ContentHint.IMPLICIT, groupId, false, SenderKeyGroupEvents.EMPTY, false);
|
||||
List<SendMessageResult> sendMessageResults = sendGroupMessage(distributionId, recipients, unidentifiedAccess, timestamp, content, ContentHint.IMPLICIT, groupId, false, SenderKeyGroupEvents.EMPTY, false, true);
|
||||
|
||||
if (aciStore.isMultiDevice()) {
|
||||
SignalServiceSyncMessage syncMessage = createSelfSendSyncMessageForStory(message, timestamp, isRecipientUpdate, manifest);
|
||||
|
@ -328,7 +309,7 @@ public class SignalServiceMessageSender {
|
|||
Content content = createCallContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.DEFAULT, Optional.empty());
|
||||
|
||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, message.isUrgent());
|
||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, message.isUrgent(), false);
|
||||
}
|
||||
|
||||
public List<SendMessageResult> sendCallMessage(List<SignalServiceAddress> recipients,
|
||||
|
@ -339,7 +320,7 @@ public class SignalServiceMessageSender {
|
|||
Content content = createCallContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.DEFAULT, Optional.empty());
|
||||
|
||||
return sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, null, message.isUrgent());
|
||||
return sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, null, message.isUrgent(), false);
|
||||
}
|
||||
|
||||
public List<SendMessageResult> sendCallMessage(DistributionId distributionId,
|
||||
|
@ -349,7 +330,7 @@ public class SignalServiceMessageSender {
|
|||
throws IOException, UntrustedIdentityException, InvalidKeyException, NoSessionException, InvalidRegistrationIdException
|
||||
{
|
||||
Content content = createCallContent(message);
|
||||
return sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp().get(), content, ContentHint.IMPLICIT, message.getGroupId(), false, SenderKeyGroupEvents.EMPTY, message.isUrgent());
|
||||
return sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp().get(), content, ContentHint.IMPLICIT, message.getGroupId(), false, SenderKeyGroupEvents.EMPTY, message.isUrgent(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -399,7 +380,7 @@ public class SignalServiceMessageSender {
|
|||
sendEvents.onMessageEncrypted();
|
||||
|
||||
long timestamp = message.getTimestamp();
|
||||
SendMessageResult result = sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, urgent);
|
||||
SendMessageResult result = sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, urgent, false);
|
||||
|
||||
sendEvents.onMessageSent();
|
||||
|
||||
|
@ -407,7 +388,7 @@ public class SignalServiceMessageSender {
|
|||
Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.of(recipient), timestamp, Collections.singletonList(result), false, Collections.emptySet());
|
||||
EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
sendMessage(localAddress, Optional.empty(), timestamp, syncMessageContent, false, null, false);
|
||||
sendMessage(localAddress, Optional.empty(), timestamp, syncMessageContent, false, null, false, false);
|
||||
}
|
||||
|
||||
sendEvents.onSyncMessageSent();
|
||||
|
@ -432,7 +413,8 @@ public class SignalServiceMessageSender {
|
|||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
||||
SenderKeyDistributionMessage message,
|
||||
Optional<byte[]> groupId,
|
||||
boolean urgent)
|
||||
boolean urgent,
|
||||
boolean story)
|
||||
throws IOException
|
||||
{
|
||||
ByteString distributionBytes = ByteString.copyFrom(message.serialize());
|
||||
|
@ -441,7 +423,7 @@ public class SignalServiceMessageSender {
|
|||
long timestamp = System.currentTimeMillis();
|
||||
|
||||
Log.d(TAG, "[" + timestamp + "] Sending SKDM to " + recipients.size() + " recipients for DistributionId " + distributionId);
|
||||
return sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, null, urgent);
|
||||
return sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, null, urgent, story);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -466,7 +448,7 @@ public class SignalServiceMessageSender {
|
|||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, contentHint, groupId);
|
||||
Optional<UnidentifiedAccess> access = unidentifiedAccess.isPresent() ? unidentifiedAccess.get().getTargetUnidentifiedAccess() : Optional.empty();
|
||||
|
||||
return sendMessage(address, access, timestamp, envelopeContent, false, null, urgent);
|
||||
return sendMessage(address, access, timestamp, envelopeContent, false, null, urgent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,7 +468,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
Content content = createMessageContent(message);
|
||||
Optional<byte[]> groupId = message.getGroupId();
|
||||
List<SendMessageResult> results = sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, contentHint, groupId, false, sendEvents, urgent);
|
||||
List<SendMessageResult> results = sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, contentHint, groupId, false, sendEvents, urgent, false);
|
||||
|
||||
sendEvents.onMessageSent();
|
||||
|
||||
|
@ -494,7 +476,7 @@ public class SignalServiceMessageSender {
|
|||
Content syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.empty(), message.getTimestamp(), results, isRecipientUpdate, Collections.emptySet());
|
||||
EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
sendMessage(localAddress, Optional.empty(), message.getTimestamp(), syncMessageContent, false, null, false);
|
||||
sendMessage(localAddress, Optional.empty(), message.getTimestamp(), syncMessageContent, false, null, false, false);
|
||||
}
|
||||
|
||||
sendEvents.onSyncMessageSent();
|
||||
|
@ -524,7 +506,7 @@ public class SignalServiceMessageSender {
|
|||
Content content = createMessageContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, contentHint, message.getGroupId());
|
||||
long timestamp = message.getTimestamp();
|
||||
List<SendMessageResult> results = sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, partialListener, cancelationSignal, urgent);
|
||||
List<SendMessageResult> results = sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, partialListener, cancelationSignal, urgent, false);
|
||||
boolean needsSyncInResults = false;
|
||||
|
||||
sendEvents.onMessageSent();
|
||||
|
@ -545,7 +527,7 @@ public class SignalServiceMessageSender {
|
|||
Content syncMessage = createMultiDeviceSentTranscriptContent(content, recipient, timestamp, results, isRecipientUpdate, Collections.emptySet());
|
||||
EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
sendMessage(localAddress, Optional.empty(), timestamp, syncMessageContent, false, null, false);
|
||||
sendMessage(localAddress, Optional.empty(), timestamp, syncMessageContent, false, null, false, false);
|
||||
}
|
||||
|
||||
sendEvents.onSyncMessageSent();
|
||||
|
@ -608,7 +590,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
return sendMessage(localAddress, Optional.empty(), timestamp, envelopeContent, false, null, urgent);
|
||||
return sendMessage(localAddress, Optional.empty(), timestamp, envelopeContent, false, null, urgent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -626,11 +608,7 @@ public class SignalServiceMessageSender {
|
|||
Content.Builder content = Content.newBuilder().setSyncMessage(syncMessage);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content.build(), ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
return getEncryptedMessage(socket, localAddress, Optional.empty(), deviceId, envelopeContent);
|
||||
}
|
||||
|
||||
public void setSoTimeoutMillis(long soTimeoutMillis) {
|
||||
socket.setSoTimeoutMillis(soTimeoutMillis);
|
||||
return getEncryptedMessage(localAddress, Optional.empty(), deviceId, envelopeContent, false);
|
||||
}
|
||||
|
||||
public void cancelInFlightRequests() {
|
||||
|
@ -763,13 +741,13 @@ public class SignalServiceMessageSender {
|
|||
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
SendMessageResult result = sendMessage(message.getDestination(), Optional.empty(), message.getTimestamp(), envelopeContent, false, null, false);
|
||||
SendMessageResult result = sendMessage(message.getDestination(), Optional.empty(), message.getTimestamp(), envelopeContent, false, null, false, false);
|
||||
|
||||
if (result.getSuccess().isNeedsSync()) {
|
||||
Content syncMessage = createMultiDeviceVerifiedContent(message, nullMessage.toByteArray());
|
||||
EnvelopeContent syncMessageContent = EnvelopeContent.encrypted(syncMessage, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
sendMessage(localAddress, Optional.empty(), message.getTimestamp(), syncMessageContent, false, null, false);
|
||||
sendMessage(localAddress, Optional.empty(), message.getTimestamp(), syncMessageContent, false, null, false, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -793,7 +771,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.empty());
|
||||
|
||||
return sendMessage(address, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, false);
|
||||
return sendMessage(address, getTargetUnidentifiedAccess(unidentifiedAccess), System.currentTimeMillis(), envelopeContent, false, null, false, false);
|
||||
}
|
||||
|
||||
private SignalServiceProtos.PniSignatureMessage createPniSignatureMessage() {
|
||||
|
@ -1678,7 +1656,8 @@ public class SignalServiceMessageSender {
|
|||
boolean online,
|
||||
PartialSendCompleteListener partialListener,
|
||||
CancelationSignal cancelationSignal,
|
||||
boolean urgent)
|
||||
boolean urgent,
|
||||
boolean story)
|
||||
throws IOException
|
||||
{
|
||||
Log.d(TAG, "[" + timestamp + "] Sending to " + recipients.size() + " recipients.");
|
||||
|
@ -1693,7 +1672,7 @@ public class SignalServiceMessageSender {
|
|||
SignalServiceAddress recipient = recipientIterator.next();
|
||||
Optional<UnidentifiedAccess> access = unidentifiedAccessIterator.next();
|
||||
futureResults.add(executor.submit(() -> {
|
||||
SendMessageResult result = sendMessage(recipient, access, timestamp, content, online, cancelationSignal, urgent);
|
||||
SendMessageResult result = sendMessage(recipient, access, timestamp, content, online, cancelationSignal, urgent, story);
|
||||
if (partialListener != null) {
|
||||
partialListener.onPartialSendComplete(result);
|
||||
}
|
||||
|
@ -1761,7 +1740,8 @@ public class SignalServiceMessageSender {
|
|||
EnvelopeContent content,
|
||||
boolean online,
|
||||
CancelationSignal cancelationSignal,
|
||||
boolean urgent)
|
||||
boolean urgent,
|
||||
boolean story)
|
||||
throws UntrustedIdentityException, IOException
|
||||
{
|
||||
enforceMaxContentSize(content);
|
||||
|
@ -1774,7 +1754,7 @@ public class SignalServiceMessageSender {
|
|||
}
|
||||
|
||||
try {
|
||||
OutgoingPushMessageList messages = getEncryptedMessages(socket, recipient, unidentifiedAccess, timestamp, content, online, urgent);
|
||||
OutgoingPushMessageList messages = getEncryptedMessages(recipient, unidentifiedAccess, timestamp, content, online, urgent, story);
|
||||
|
||||
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());
|
||||
|
@ -1788,7 +1768,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
if (!unidentifiedAccess.isPresent()) {
|
||||
try {
|
||||
SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, Optional.empty()).blockingGet()).getResultOrThrow();
|
||||
SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, Optional.empty(), story).blockingGet()).getResultOrThrow();
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || aciStore.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
} catch (InvalidUnidentifiedAccessHeaderException | UnregisteredUserException | MismatchedDevicesException | StaleDevicesException e) {
|
||||
// Non-technical failures shouldn't be retried with socket
|
||||
|
@ -1801,7 +1781,7 @@ public class SignalServiceMessageSender {
|
|||
}
|
||||
} else if (unidentifiedAccess.isPresent()) {
|
||||
try {
|
||||
SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, unidentifiedAccess).blockingGet()).getResultOrThrow();
|
||||
SendMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.send(messages, unidentifiedAccess, story).blockingGet()).getResultOrThrow();
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || aciStore.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
} catch (InvalidUnidentifiedAccessHeaderException | UnregisteredUserException | MismatchedDevicesException | StaleDevicesException e) {
|
||||
// Non-technical failures shouldn't be retried with socket
|
||||
|
@ -1821,7 +1801,7 @@ public class SignalServiceMessageSender {
|
|||
throw new CancelationException();
|
||||
}
|
||||
|
||||
SendMessageResponse response = socket.sendMessage(messages, unidentifiedAccess);
|
||||
SendMessageResponse response = socket.sendMessage(messages, unidentifiedAccess, story);
|
||||
|
||||
return SendMessageResult.success(recipient, messages.getDevices(), response.sentUnidentified(), response.getNeedsSync() || aciStore.isMultiDevice(), System.currentTimeMillis() - startTime, content.getContent());
|
||||
|
||||
|
@ -1863,7 +1843,8 @@ public class SignalServiceMessageSender {
|
|||
Optional<byte[]> groupId,
|
||||
boolean online,
|
||||
SenderKeyGroupEvents sendEvents,
|
||||
boolean urgent)
|
||||
boolean urgent,
|
||||
boolean story)
|
||||
throws IOException, UntrustedIdentityException, NoSessionException, InvalidKeyException, InvalidRegistrationIdException
|
||||
{
|
||||
if (recipients.isEmpty()) {
|
||||
|
@ -1900,7 +1881,7 @@ public class SignalServiceMessageSender {
|
|||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<SendMessageResult> results = sendSenderKeyDistributionMessage(distributionId, needsSenderKey, access, message, groupId, urgent);
|
||||
List<SendMessageResult> results = sendSenderKeyDistributionMessage(distributionId, needsSenderKey, access, message, groupId, urgent, story);
|
||||
|
||||
List<SignalServiceAddress> successes = results.stream()
|
||||
.filter(SendMessageResult::isSuccess)
|
||||
|
@ -1962,7 +1943,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
try {
|
||||
try {
|
||||
SendGroupMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.sendToGroup(ciphertext, joinedUnidentifiedAccess, timestamp, online, urgent).blockingGet()).getResultOrThrow();
|
||||
SendGroupMessageResponse response = new MessagingService.SendResponseProcessor<>(messagingService.sendToGroup(ciphertext, joinedUnidentifiedAccess, timestamp, online, urgent, story).blockingGet()).getResultOrThrow();
|
||||
return transformGroupResponseToMessageResults(targetInfo.devices, response, content);
|
||||
} catch (InvalidUnidentifiedAccessHeaderException | NotFoundException | GroupMismatchedDevicesException | GroupStaleDevicesException e) {
|
||||
// Non-technical failures shouldn't be retried with socket
|
||||
|
@ -1973,7 +1954,7 @@ public class SignalServiceMessageSender {
|
|||
Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Pipe failed, falling back... (" + e.getClass().getSimpleName() + ": " + e.getMessage() + ")");
|
||||
}
|
||||
|
||||
SendGroupMessageResponse response = socket.sendGroupMessage(ciphertext, joinedUnidentifiedAccess, timestamp, online, urgent);
|
||||
SendGroupMessageResponse response = socket.sendGroupMessage(ciphertext, joinedUnidentifiedAccess, timestamp, online, urgent, true);
|
||||
return transformGroupResponseToMessageResults(targetInfo.devices, response, content);
|
||||
} catch (GroupMismatchedDevicesException e) {
|
||||
Log.w(TAG, "[sendGroupMessage][" + timestamp + "] Handling mismatched devices. (" + e.getMessage() + ")");
|
||||
|
@ -2138,13 +2119,13 @@ public class SignalServiceMessageSender {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket,
|
||||
SignalServiceAddress recipient,
|
||||
private OutgoingPushMessageList getEncryptedMessages(SignalServiceAddress recipient,
|
||||
Optional<UnidentifiedAccess> unidentifiedAccess,
|
||||
long timestamp,
|
||||
EnvelopeContent plaintext,
|
||||
boolean online,
|
||||
boolean urgent)
|
||||
boolean urgent,
|
||||
boolean story)
|
||||
throws IOException, InvalidKeyException, UntrustedIdentityException
|
||||
{
|
||||
List<OutgoingPushMessage> messages = new LinkedList<>();
|
||||
|
@ -2161,18 +2142,18 @@ public class SignalServiceMessageSender {
|
|||
|
||||
for (int deviceId : deviceIds) {
|
||||
if (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID || aciStore.containsSession(new SignalProtocolAddress(recipient.getIdentifier(), deviceId))) {
|
||||
messages.add(getEncryptedMessage(socket, recipient, unidentifiedAccess, deviceId, plaintext));
|
||||
messages.add(getEncryptedMessage(recipient, unidentifiedAccess, deviceId, plaintext, story));
|
||||
}
|
||||
}
|
||||
|
||||
return new OutgoingPushMessageList(recipient.getIdentifier(), timestamp, messages, online, urgent);
|
||||
}
|
||||
|
||||
private OutgoingPushMessage getEncryptedMessage(PushServiceSocket socket,
|
||||
SignalServiceAddress recipient,
|
||||
private OutgoingPushMessage getEncryptedMessage(SignalServiceAddress recipient,
|
||||
Optional<UnidentifiedAccess> unidentifiedAccess,
|
||||
int deviceId,
|
||||
EnvelopeContent plaintext)
|
||||
EnvelopeContent plaintext,
|
||||
boolean story)
|
||||
throws IOException, InvalidKeyException, UntrustedIdentityException
|
||||
{
|
||||
SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(recipient.getIdentifier(), deviceId);
|
||||
|
@ -2180,7 +2161,7 @@ public class SignalServiceMessageSender {
|
|||
|
||||
if (!aciStore.containsSession(signalProtocolAddress)) {
|
||||
try {
|
||||
List<PreKeyBundle> preKeys = socket.getPreKeys(recipient, unidentifiedAccess, deviceId);
|
||||
List<PreKeyBundle> preKeys = getPreKeys(recipient, unidentifiedAccess, deviceId, story);
|
||||
|
||||
for (PreKeyBundle preKey : preKeys) {
|
||||
try {
|
||||
|
@ -2207,6 +2188,19 @@ public class SignalServiceMessageSender {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private List<PreKeyBundle> getPreKeys(SignalServiceAddress recipient, Optional<UnidentifiedAccess> unidentifiedAccess, int deviceId, boolean story) throws IOException {
|
||||
try {
|
||||
return socket.getPreKeys(recipient, unidentifiedAccess, deviceId);
|
||||
} catch (NonSuccessfulResponseCodeException e) {
|
||||
if (e.getCode() == 401 && story) {
|
||||
return socket.getPreKeys(recipient, Optional.empty(), deviceId);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMismatchedDevices(PushServiceSocket socket, SignalServiceAddress recipient,
|
||||
MismatchedDevices mismatchedDevices)
|
||||
throws IOException, UntrustedIdentityException
|
||||
|
|
|
@ -43,7 +43,7 @@ public class MessagingService {
|
|||
this.signalWebSocket = signalWebSocket;
|
||||
}
|
||||
|
||||
public Single<ServiceResponse<SendMessageResponse>> send(OutgoingPushMessageList list, Optional<UnidentifiedAccess> unidentifiedAccess) {
|
||||
public Single<ServiceResponse<SendMessageResponse>> send(OutgoingPushMessageList list, Optional<UnidentifiedAccess> unidentifiedAccess, boolean story) {
|
||||
List<String> headers = new LinkedList<String>() {{
|
||||
add("content-type:application/json");
|
||||
}};
|
||||
|
@ -51,7 +51,7 @@ public class MessagingService {
|
|||
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
.setVerb("PUT")
|
||||
.setPath(String.format("/v1/messages/%s", list.getDestination()))
|
||||
.setPath(String.format("/v1/messages/%s?story=%s", list.getDestination(), story ? "true" : "false"))
|
||||
.addAllHeaders(headers)
|
||||
.setBody(ByteString.copyFrom(JsonUtil.toJson(list).getBytes()))
|
||||
.build();
|
||||
|
@ -72,13 +72,13 @@ public class MessagingService {
|
|||
.onErrorReturn(ServiceResponse::forUnknownError);
|
||||
}
|
||||
|
||||
public Single<ServiceResponse<SendGroupMessageResponse>> sendToGroup(byte[] body, byte[] joinedUnidentifiedAccess, long timestamp, boolean online, boolean urgent) {
|
||||
public Single<ServiceResponse<SendGroupMessageResponse>> sendToGroup(byte[] body, byte[] joinedUnidentifiedAccess, long timestamp, boolean online, boolean urgent, boolean story) {
|
||||
List<String> headers = new LinkedList<String>() {{
|
||||
add("content-type:application/vnd.signal-messenger.mrm");
|
||||
add("Unidentified-Access-Key:" + Base64.encodeBytes(joinedUnidentifiedAccess));
|
||||
}};
|
||||
|
||||
String path = String.format(Locale.US, "/v1/messages/multi_recipient?ts=%s&online=%s&urgent=%s", timestamp, online, urgent);
|
||||
String path = String.format(Locale.US, "/v1/messages/multi_recipient?ts=%s&online=%s&urgent=%s&story=%s", timestamp, online, urgent, story);
|
||||
|
||||
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
|
|
|
@ -220,8 +220,8 @@ public class PushServiceSocket {
|
|||
private static final String DEVICE_PATH = "/v1/devices/%s";
|
||||
|
||||
private static final String DIRECTORY_AUTH_PATH = "/v1/directory/auth";
|
||||
private static final String MESSAGE_PATH = "/v1/messages/%s";
|
||||
private static final String GROUP_MESSAGE_PATH = "/v1/messages/multi_recipient?ts=%s&online=%s&urgent=%s";
|
||||
private static final String MESSAGE_PATH = "/v1/messages/%s?story=%s";
|
||||
private static final String GROUP_MESSAGE_PATH = "/v1/messages/multi_recipient?ts=%s&online=%s&urgent=%s&story=%s";
|
||||
private static final String SENDER_ACK_MESSAGE_PATH = "/v1/messages/%s/%d";
|
||||
private static final String UUID_ACK_MESSAGE_PATH = "/v1/messages/uuid/%s";
|
||||
private static final String ATTACHMENT_V2_PATH = "/v2/attachments/form/upload";
|
||||
|
@ -486,12 +486,12 @@ public class PushServiceSocket {
|
|||
return JsonUtil.fromJson(responseText, SenderCertificate.class).getCertificate();
|
||||
}
|
||||
|
||||
public SendGroupMessageResponse sendGroupMessage(byte[] body, byte[] joinedUnidentifiedAccess, long timestamp, boolean online, boolean urgent)
|
||||
public SendGroupMessageResponse sendGroupMessage(byte[] body, byte[] joinedUnidentifiedAccess, long timestamp, boolean online, boolean urgent, boolean story)
|
||||
throws IOException
|
||||
{
|
||||
ServiceConnectionHolder connectionHolder = (ServiceConnectionHolder) getRandom(serviceClients, random);
|
||||
|
||||
String path = String.format(Locale.US, GROUP_MESSAGE_PATH, timestamp, online, urgent);
|
||||
String path = String.format(Locale.US, GROUP_MESSAGE_PATH, timestamp, online, urgent, story);
|
||||
|
||||
Request.Builder requestBuilder = new Request.Builder();
|
||||
requestBuilder.url(String.format("%s%s", connectionHolder.getUrl(), path));
|
||||
|
@ -544,11 +544,11 @@ public class PushServiceSocket {
|
|||
}
|
||||
}
|
||||
|
||||
public SendMessageResponse sendMessage(OutgoingPushMessageList bundle, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
public SendMessageResponse sendMessage(OutgoingPushMessageList bundle, Optional<UnidentifiedAccess> unidentifiedAccess, boolean story)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
String responseText = makeServiceRequest(String.format(MESSAGE_PATH, bundle.getDestination()), "PUT", JsonUtil.toJson(bundle), NO_HEADERS, unidentifiedAccess);
|
||||
String responseText = makeServiceRequest(String.format(MESSAGE_PATH, bundle.getDestination(), story ? "true" : "false"), "PUT", JsonUtil.toJson(bundle), NO_HEADERS, unidentifiedAccess);
|
||||
SendMessageResponse response = JsonUtil.fromJson(responseText, SendMessageResponse.class);
|
||||
|
||||
response.setSentUnidentfied(unidentifiedAccess.isPresent());
|
||||
|
@ -559,8 +559,10 @@ public class PushServiceSocket {
|
|||
}
|
||||
}
|
||||
|
||||
public SignalServiceMessagesResult getMessages() throws IOException {
|
||||
try (Response response = makeServiceRequest(String.format(MESSAGE_PATH, ""), "GET", (RequestBody) null, NO_HEADERS, NO_HANDLER, Optional.empty())) {
|
||||
public SignalServiceMessagesResult getMessages(boolean allowStories) throws IOException {
|
||||
Map<String, String> headers = Collections.singletonMap("X-Signal-Receive-Stories", allowStories ? "true" : "false");
|
||||
|
||||
try (Response response = makeServiceRequest(String.format(MESSAGE_PATH, ""), "GET", (RequestBody) null, headers, NO_HANDLER, Optional.empty())) {
|
||||
validateServiceResponse(response);
|
||||
|
||||
List<SignalServiceEnvelopeEntity> envelopes = readBodyJson(response.body(), SignalServiceEnvelopeEntityList.class).getMessages();
|
||||
|
|
|
@ -18,9 +18,10 @@ public class SendGroupMessageResponse {
|
|||
public SendGroupMessageResponse() {}
|
||||
|
||||
public Set<ServiceId> getUnsentTargets() {
|
||||
Set<ServiceId> serviceIds = new HashSet<>(uuids404.length);
|
||||
String[] uuids = uuids404 != null ? uuids404 : new String[0];
|
||||
Set<ServiceId> serviceIds = new HashSet<>(uuids.length);
|
||||
|
||||
for (String raw : uuids404) {
|
||||
for (String raw : uuids) {
|
||||
ServiceId parsed = ServiceId.parseOrNull(raw);
|
||||
if (parsed != null) {
|
||||
serviceIds.add(parsed);
|
||||
|
|
|
@ -66,14 +66,15 @@ public class WebSocketConnection extends WebSocketListener {
|
|||
|
||||
private final String name;
|
||||
private final String wsUri;
|
||||
private final TrustStore trustStore;
|
||||
private final Optional<CredentialsProvider> credentialsProvider;
|
||||
private final String signalAgent;
|
||||
private final TrustStore trustStore;
|
||||
private final Optional<CredentialsProvider> credentialsProvider;
|
||||
private final String signalAgent;
|
||||
private final HealthMonitor healthMonitor;
|
||||
private final List<Interceptor> interceptors;
|
||||
private final Optional<Dns> dns;
|
||||
private final Optional<SignalProxy> signalProxy;
|
||||
private final BehaviorSubject<WebSocketConnectionState> webSocketState;
|
||||
private final boolean allowStories;
|
||||
|
||||
private WebSocket client;
|
||||
|
||||
|
@ -81,8 +82,9 @@ public class WebSocketConnection extends WebSocketListener {
|
|||
SignalServiceConfiguration serviceConfiguration,
|
||||
Optional<CredentialsProvider> credentialsProvider,
|
||||
String signalAgent,
|
||||
HealthMonitor healthMonitor) {
|
||||
this(name, serviceConfiguration, credentialsProvider, signalAgent, healthMonitor, "");
|
||||
HealthMonitor healthMonitor,
|
||||
boolean allowStories) {
|
||||
this(name, serviceConfiguration, credentialsProvider, signalAgent, healthMonitor, "", allowStories);
|
||||
}
|
||||
|
||||
public WebSocketConnection(String name,
|
||||
|
@ -90,7 +92,8 @@ public class WebSocketConnection extends WebSocketListener {
|
|||
Optional<CredentialsProvider> credentialsProvider,
|
||||
String signalAgent,
|
||||
HealthMonitor healthMonitor,
|
||||
String extraPathUri)
|
||||
String extraPathUri,
|
||||
boolean allowStories)
|
||||
{
|
||||
this.name = "[" + name + ":" + System.identityHashCode(this) + "]";
|
||||
this.trustStore = serviceConfiguration.getSignalServiceUrls()[0].getTrustStore();
|
||||
|
@ -101,6 +104,7 @@ public class WebSocketConnection extends WebSocketListener {
|
|||
this.signalProxy = serviceConfiguration.getSignalProxy();
|
||||
this.healthMonitor = healthMonitor;
|
||||
this.webSocketState = BehaviorSubject.createDefault(WebSocketConnectionState.DISCONNECTED);
|
||||
this.allowStories = allowStories;
|
||||
|
||||
String uri = serviceConfiguration.getSignalServiceUrls()[0].getUrl().replace("https://", "wss://").replace("http://", "ws://");
|
||||
|
||||
|
@ -156,6 +160,8 @@ public class WebSocketConnection extends WebSocketListener {
|
|||
requestBuilder.addHeader("X-Signal-Agent", signalAgent);
|
||||
}
|
||||
|
||||
requestBuilder.addHeader("X-Signal-Receive-Stories", allowStories ? "true" : "false");
|
||||
|
||||
webSocketState.onNext(WebSocketConnectionState.CONNECTING);
|
||||
|
||||
this.client = okHttpClient.newWebSocket(requestBuilder.build(), this);
|
||||
|
|
Ładowanie…
Reference in New Issue