mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-26 22:20:20 +00:00
Add basic support for receiving messages at your PNI.
We haven't implemented merging yet, so this is still very basic, but it "works".
This commit is contained in:
@@ -424,6 +424,14 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from(R.string.preferences__internal_clear_all_profile_keys),
|
||||
summary = DSLSettingsText.from(R.string.preferences__internal_clear_all_profile_keys_description),
|
||||
onClick = {
|
||||
clearAllProfileKeys()
|
||||
}
|
||||
)
|
||||
|
||||
dividerPref()
|
||||
|
||||
sectionHeaderPref(R.string.ConversationListTabs__stories)
|
||||
@@ -548,6 +556,7 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
|
||||
private fun clearAllServiceIds() {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle("Clear all serviceIds?")
|
||||
.setMessage("Are you sure? Never do this on a non-test device.")
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
SignalDatabase.recipients.debugClearServiceIds()
|
||||
@@ -558,4 +567,18 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun clearAllProfileKeys() {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle("Clear all profile keys?")
|
||||
.setMessage("Are you sure? Never do this on a non-test device.")
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
SignalDatabase.recipients.debugClearServiceIds()
|
||||
Toast.makeText(context, "Cleared all profile keys.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { d, _ ->
|
||||
d.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,12 +60,27 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
|
||||
)
|
||||
|
||||
if (!recipient.isGroup) {
|
||||
val serviceId = recipient.serviceId.map(ServiceId::toString).orElse("null")
|
||||
longClickPref(
|
||||
title = DSLSettingsText.from("ServiceId"),
|
||||
summary = DSLSettingsText.from(serviceId),
|
||||
onLongClick = { copyToClipboard(serviceId) }
|
||||
)
|
||||
if (recipient.isSelf) {
|
||||
val aci: String = SignalStore.account().aci?.toString() ?: "null"
|
||||
longClickPref(
|
||||
title = DSLSettingsText.from("ACI"),
|
||||
summary = DSLSettingsText.from(aci),
|
||||
onLongClick = { copyToClipboard(aci) }
|
||||
)
|
||||
val pni: String = SignalStore.account().pni?.toString() ?: "null"
|
||||
longClickPref(
|
||||
title = DSLSettingsText.from("PNI"),
|
||||
summary = DSLSettingsText.from(pni),
|
||||
onLongClick = { copyToClipboard(pni) }
|
||||
)
|
||||
} else {
|
||||
val serviceId: String = recipient.serviceId.map(ServiceId::toString).orElse("null")
|
||||
longClickPref(
|
||||
title = DSLSettingsText.from("ServiceId"),
|
||||
summary = DSLSettingsText.from(serviceId),
|
||||
onLongClick = { copyToClipboard(serviceId) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.groupId != null) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public final class SignalServiceDataStoreImpl implements SignalServiceDataStore
|
||||
if (accountIdentifier.equals(SignalStore.account().getAci())) {
|
||||
return aciStore;
|
||||
} else if (accountIdentifier.equals(SignalStore.account().getPni())) {
|
||||
throw new AssertionError("Not to be used yet!");
|
||||
return pniStore;
|
||||
} else {
|
||||
throw new IllegalArgumentException("No matching store found for " + accountIdentifier);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,8 @@ public class PushDatabase extends Database {
|
||||
Util.isEmpty(content) ? null : Base64.decode(content),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_RECEIVED_TIMESTAMP)),
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_DELIVERED_TIMESTAMP)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(SERVER_GUID)));
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(SERVER_GUID)),
|
||||
"");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
@@ -178,7 +179,8 @@ public class PushDatabase extends Database {
|
||||
content != null ? Base64.decode(content) : null,
|
||||
serverReceivedTimestamp,
|
||||
serverDeliveredTimestamp,
|
||||
serverGuid);
|
||||
serverGuid,
|
||||
"");
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
@@ -2932,6 +2932,21 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||
SERVICE_ID to null,
|
||||
PNI_COLUMN to null
|
||||
)
|
||||
.where("$ID != ?", Recipient.self().id)
|
||||
.run()
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be used for debugging! A very destructive action that clears all known profile keys and credentials.
|
||||
*/
|
||||
fun debugClearProfileKeys() {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(
|
||||
PROFILE_KEY to null,
|
||||
PROFILE_KEY_CREDENTIAL to null
|
||||
)
|
||||
.where("$ID != ?", Recipient.self().id)
|
||||
.run()
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.whispersystems.signalservice.api.crypto.ContentHint;
|
||||
import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
|
||||
@@ -76,8 +77,26 @@ public final class MessageDecryptionUtil {
|
||||
* caller.
|
||||
*/
|
||||
public static @NonNull DecryptionResult decrypt(@NonNull Context context, @NonNull SignalServiceEnvelope envelope) {
|
||||
SignalServiceAccountDataStore protocolStore = ApplicationDependencies.getProtocolStore().aci();
|
||||
SignalServiceAddress localAddress = new SignalServiceAddress(SignalStore.account().requireAci(), Recipient.self().requireE164());
|
||||
ServiceId aci = SignalStore.account().requireAci();
|
||||
ServiceId pni = SignalStore.account().requirePni();
|
||||
|
||||
ServiceId destination;
|
||||
if (!FeatureFlags.usePnpCds()) {
|
||||
destination = aci;
|
||||
} else if (envelope.hasDestinationUuid()) {
|
||||
destination = ServiceId.parseOrThrow(envelope.getDestinationUuid());
|
||||
} else {
|
||||
Log.w(TAG, "No destinationUuid set! Defaulting to ACI.");
|
||||
destination = aci;
|
||||
}
|
||||
|
||||
if (!destination.equals(aci) && !destination.equals(pni)) {
|
||||
Log.w(TAG, "Destination of " + destination + " does not match our ACI (" + aci + ") or PNI (" + pni + ")! Defaulting to ACI.");
|
||||
destination = aci;
|
||||
}
|
||||
|
||||
SignalServiceAccountDataStore protocolStore = ApplicationDependencies.getProtocolStore().get(destination);
|
||||
SignalServiceAddress localAddress = new SignalServiceAddress(SignalStore.account().requireAci(), SignalStore.account().getE164());
|
||||
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, SignalStore.account().getDeviceId(), protocolStore, ReentrantSessionLock.INSTANCE, UnidentifiedAccessUtil.getCertificateValidator());
|
||||
List<Job> jobs = new LinkedList<>();
|
||||
|
||||
|
||||
@@ -2713,7 +2713,9 @@
|
||||
<string name="preferences__internal_clear_history" translatable="false">Clear history</string>
|
||||
<string name="preferences__internal_clear_history_description" translatable="false">Clears all CDS history, meaning the next sync will consider all numbers to be new.</string>
|
||||
<string name="preferences__internal_clear_all_service_ids" translatable="false">Clear all service IDs</string>
|
||||
<string name="preferences__internal_clear_all_service_ids_description" translatable="false">Clears all known service IDs. Do not use on your personal device!</string>
|
||||
<string name="preferences__internal_clear_all_service_ids_description" translatable="false">Clears all known service IDs (except your own). Do not use on your personal device!</string>
|
||||
<string name="preferences__internal_clear_all_profile_keys" translatable="false">Clear all profile keys</string>
|
||||
<string name="preferences__internal_clear_all_profile_keys_description" translatable="false">Clears all known profile keys (except your own). Do not use on your personal device!</string>
|
||||
|
||||
|
||||
<!-- Payments -->
|
||||
|
||||
@@ -212,7 +212,8 @@ public class SignalServiceMessageReceiver {
|
||||
entity.getContent(),
|
||||
entity.getServerTimestamp(),
|
||||
messageResult.getServerDeliveredTimestamp(),
|
||||
entity.getServerUuid());
|
||||
entity.getServerUuid(),
|
||||
entity.getDestinationUuid());
|
||||
} else {
|
||||
envelope = new SignalServiceEnvelope(entity.getType(),
|
||||
entity.getTimestamp(),
|
||||
|
||||
@@ -195,7 +195,7 @@ public class SignalServiceCipher {
|
||||
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
|
||||
|
||||
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.empty());
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationUuid());
|
||||
|
||||
signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress));
|
||||
} else if (envelope.isSignalMessage()) {
|
||||
@@ -203,10 +203,10 @@ public class SignalServiceCipher {
|
||||
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
|
||||
|
||||
paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.empty());
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationUuid());
|
||||
} else if (envelope.isPlaintextContent()) {
|
||||
paddedMessage = new PlaintextContent(ciphertext).getBody();
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.empty());
|
||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.empty(), envelope.getDestinationUuid());
|
||||
} else if (envelope.isUnidentifiedSender()) {
|
||||
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orElse(null), localDeviceId));
|
||||
DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, ciphertext, envelope.getServerReceivedTimestamp());
|
||||
@@ -224,7 +224,7 @@ public class SignalServiceCipher {
|
||||
}
|
||||
|
||||
paddedMessage = result.getPaddedMessage();
|
||||
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), needsReceipt, envelope.getServerGuid(), groupId);
|
||||
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), needsReceipt, envelope.getServerGuid(), groupId, envelope.getDestinationUuid());
|
||||
} else {
|
||||
throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
|
||||
}
|
||||
|
||||
@@ -12,12 +12,14 @@ import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import org.whispersystems.signalservice.api.push.ACI;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope;
|
||||
import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceEnvelopeProto;
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class represents an encrypted Signal Service envelope.
|
||||
@@ -62,13 +64,15 @@ public class SignalServiceEnvelope {
|
||||
byte[] content,
|
||||
long serverReceivedTimestamp,
|
||||
long serverDeliveredTimestamp,
|
||||
String uuid)
|
||||
String uuid,
|
||||
String destinationUuid)
|
||||
{
|
||||
Envelope.Builder builder = Envelope.newBuilder()
|
||||
.setType(Envelope.Type.valueOf(type))
|
||||
.setSourceDevice(senderDevice)
|
||||
.setTimestamp(timestamp)
|
||||
.setServerTimestamp(serverReceivedTimestamp);
|
||||
.setServerTimestamp(serverReceivedTimestamp)
|
||||
.setDestinationUuid(destinationUuid);
|
||||
|
||||
if (sender.isPresent()) {
|
||||
builder.setSourceUuid(sender.get().getServiceId().toString());
|
||||
@@ -249,6 +253,14 @@ public class SignalServiceEnvelope {
|
||||
return envelope.getType().getNumber() == Envelope.Type.PLAINTEXT_CONTENT_VALUE;
|
||||
}
|
||||
|
||||
public boolean hasDestinationUuid() {
|
||||
return envelope.hasDestinationUuid() && UuidUtil.isUuid(envelope.getDestinationUuid());
|
||||
}
|
||||
|
||||
public String getDestinationUuid() {
|
||||
return envelope.getDestinationUuid();
|
||||
}
|
||||
|
||||
public byte[] serialize() {
|
||||
SignalServiceEnvelopeProto.Builder builder = SignalServiceEnvelopeProto.newBuilder()
|
||||
.setType(getType())
|
||||
@@ -277,6 +289,11 @@ public class SignalServiceEnvelope {
|
||||
builder.setServerGuid(getServerGuid());
|
||||
}
|
||||
|
||||
if (hasDestinationUuid()) {
|
||||
builder.setDestinationUuid(getDestinationUuid().toString());
|
||||
}
|
||||
|
||||
|
||||
return builder.build().toByteArray();
|
||||
}
|
||||
|
||||
@@ -296,6 +313,7 @@ public class SignalServiceEnvelope {
|
||||
proto.hasContent() ? proto.getContent().toByteArray() : null,
|
||||
proto.getServerReceivedTimestamp(),
|
||||
proto.getServerDeliveredTimestamp(),
|
||||
proto.getServerGuid());
|
||||
proto.getServerGuid(),
|
||||
proto.getDestinationUuid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public final class SignalServiceMetadata {
|
||||
private final boolean needsReceipt;
|
||||
private final String serverGuid;
|
||||
private final Optional<byte[]> groupId;
|
||||
private final String destinationUuid;
|
||||
|
||||
public SignalServiceMetadata(SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
@@ -22,7 +23,8 @@ public final class SignalServiceMetadata {
|
||||
long serverDeliveredTimestamp,
|
||||
boolean needsReceipt,
|
||||
String serverGuid,
|
||||
Optional<byte[]> groupId)
|
||||
Optional<byte[]> groupId,
|
||||
String destinationUuid)
|
||||
{
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
@@ -32,6 +34,7 @@ public final class SignalServiceMetadata {
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serverGuid = serverGuid;
|
||||
this.groupId = groupId;
|
||||
this.destinationUuid = destinationUuid != null ? destinationUuid : "";
|
||||
}
|
||||
|
||||
public SignalServiceAddress getSender() {
|
||||
@@ -65,4 +68,8 @@ public final class SignalServiceMetadata {
|
||||
public Optional<byte[]> getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public String getDestinationUuid() {
|
||||
return destinationUuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ public class SignalServiceEnvelopeEntity {
|
||||
@JsonProperty
|
||||
private int sourceDevice;
|
||||
|
||||
@JsonProperty
|
||||
private String destinationUuid;
|
||||
|
||||
@JsonProperty
|
||||
private byte[] message;
|
||||
|
||||
@@ -79,4 +82,8 @@ public class SignalServiceEnvelopeEntity {
|
||||
public String getServerUuid() {
|
||||
return guid;
|
||||
}
|
||||
|
||||
public String getDestinationUuid() {
|
||||
return destinationUuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ public final class SignalServiceMetadataProtobufSerializer {
|
||||
.setTimestamp(metadata.getTimestamp())
|
||||
.setServerReceivedTimestamp(metadata.getServerReceivedTimestamp())
|
||||
.setServerDeliveredTimestamp(metadata.getServerDeliveredTimestamp())
|
||||
.setServerGuid(metadata.getServerGuid());
|
||||
.setServerGuid(metadata.getServerGuid())
|
||||
.setDestinationUuid(metadata.getDestinationUuid());
|
||||
|
||||
if (metadata.getGroupId().isPresent()) {
|
||||
builder.setGroupId(ByteString.copyFrom(metadata.getGroupId().get()));
|
||||
@@ -37,6 +38,7 @@ public final class SignalServiceMetadataProtobufSerializer {
|
||||
metadata.getServerDeliveredTimestamp(),
|
||||
metadata.getNeedsReceipt(),
|
||||
metadata.getServerGuid(),
|
||||
Optional.ofNullable(metadata.getGroupId()).map(ByteString::toByteArray));
|
||||
Optional.ofNullable(metadata.getGroupId()).map(ByteString::toByteArray),
|
||||
metadata.getDestinationUuid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ message SignalServiceEnvelopeProto {
|
||||
optional int64 serverReceivedTimestamp = 8;
|
||||
optional int64 serverDeliveredTimestamp = 9;
|
||||
optional string serverGuid = 10;
|
||||
optional string destinationUuid = 11;
|
||||
}
|
||||
|
||||
message MetadataProto {
|
||||
@@ -43,6 +44,7 @@ message MetadataProto {
|
||||
optional bool needsReceipt = 4;
|
||||
optional string serverGuid = 7;
|
||||
optional bytes groupId = 8;
|
||||
optional string destinationUuid = 9;
|
||||
}
|
||||
|
||||
message AddressProto {
|
||||
|
||||
Reference in New Issue
Block a user