Handle PniChangeNumber

This commit is contained in:
AsamK 2022-10-16 20:07:33 +02:00
parent 94d79692df
commit 45a5795c9c
7 changed files with 89 additions and 9 deletions

View file

@ -14,7 +14,7 @@ repositories {
} }
dependencies { dependencies {
implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_61") implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_62")
implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4") implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.4")
implementation("com.google.protobuf", "protobuf-javalite", "3.21.6") implementation("com.google.protobuf", "protobuf-javalite", "3.21.6")
implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") implementation("org.bouncycastle", "bcprov-jdk15on", "1.70")

View file

@ -11,12 +11,15 @@ import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.util.KeyUtils; import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.NumberVerificationUtils; import org.asamk.signal.manager.util.NumberVerificationUtils;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest; import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException; import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
@ -111,6 +114,19 @@ public class AccountHelper {
context.getAccountFileUpdater().updateAccountIdentifiers(account.getNumber(), account.getAci()); context.getAccountFileUpdater().updateAccountIdentifiers(account.getNumber(), account.getAci());
} }
public void setPni(
final PNI updatedPni,
final IdentityKeyPair pniIdentityKeyPair,
final SignedPreKeyRecord pniSignedPreKey,
final int localPniRegistrationId
) throws IOException {
account.setPni(updatedPni, pniIdentityKeyPair, pniSignedPreKey, localPniRegistrationId);
context.getPreKeyHelper().refreshPreKeysIfNecessary(ServiceIdType.PNI);
if (account.getPni() == null || !account.getPni().equals(updatedPni)) {
context.getGroupV2Helper().clearAuthCredentialCache();
}
}
public void startChangeNumber( public void startChangeNumber(
String newNumber, String captcha, boolean voiceVerification String newNumber, String captcha, boolean voiceVerification
) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException { ) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException {

View file

@ -77,6 +77,10 @@ class GroupV2Helper {
this.context = context; this.context = context;
} }
void clearAuthCredentialCache() {
groupApiCredentials = null;
}
DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException { DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException {
try { try {
final var groupsV2AuthorizationString = getGroupAuthForToday(groupSecretParams); final var groupsV2AuthorizationString = getGroupAuthForToday(groupSecretParams);

View file

@ -42,8 +42,10 @@ import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
import org.signal.libsignal.metadata.ProtocolNoSessionException; import org.signal.libsignal.metadata.ProtocolNoSessionException;
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException; import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.signal.libsignal.metadata.SelfSendException; import org.signal.libsignal.metadata.SelfSendException;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidMessageException; import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.message.DecryptionErrorMessage; import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -58,6 +60,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage; import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage; import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOperationMessage;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
@ -304,7 +307,10 @@ public final class IncomingMessageHandler {
if (content.getSyncMessage().isPresent()) { if (content.getSyncMessage().isPresent()) {
var syncMessage = content.getSyncMessage().get(); var syncMessage = content.getSyncMessage().get();
actions.addAll(handleSyncMessage(syncMessage, senderDeviceAddress, receiveConfig.ignoreAttachments())); actions.addAll(handleSyncMessage(envelope,
syncMessage,
senderDeviceAddress,
receiveConfig.ignoreAttachments()));
} }
return actions; return actions;
@ -364,7 +370,10 @@ public final class IncomingMessageHandler {
} }
private List<HandleAction> handleSyncMessage( private List<HandleAction> handleSyncMessage(
final SignalServiceSyncMessage syncMessage, final DeviceAddress sender, final boolean ignoreAttachments final SignalServiceEnvelope envelope,
final SignalServiceSyncMessage syncMessage,
final DeviceAddress sender,
final boolean ignoreAttachments
) { ) {
var actions = new ArrayList<HandleAction>(); var actions = new ArrayList<HandleAction>();
account.setMultiDevice(true); account.setMultiDevice(true);
@ -519,7 +528,26 @@ public final class IncomingMessageHandler {
pniIdentity.getPrivateKey().toByteArray())); pniIdentity.getPrivateKey().toByteArray()));
actions.add(RefreshPreKeysAction.create()); actions.add(RefreshPreKeysAction.create());
} }
// TODO handle PniChangeNumber if (syncMessage.getPniChangeNumber().isPresent()) {
final var pniChangeNumber = syncMessage.getPniChangeNumber().get();
logger.debug("Received PNI change number sync message, applying.");
if (pniChangeNumber.hasIdentityKeyPair()
&& pniChangeNumber.hasRegistrationId()
&& pniChangeNumber.hasSignedPreKey()
&& !envelope.getUpdatedPni().isEmpty()) {
logger.debug("New PNI: {}", envelope.getUpdatedPni());
try {
final var updatedPni = PNI.parseOrThrow(envelope.getUpdatedPni());
context.getAccountHelper()
.setPni(updatedPni,
new IdentityKeyPair(pniChangeNumber.getIdentityKeyPair().toByteArray()),
new SignedPreKeyRecord(pniChangeNumber.getSignedPreKey().toByteArray()),
pniChangeNumber.getRegistrationId());
} catch (Exception e) {
logger.warn("Failed to handle change number message", e);
}
}
}
return actions; return actions;
} }

View file

@ -352,7 +352,8 @@ public class SendHelper {
contentHint, contentHint,
message, message,
SignalServiceMessageSender.SenderKeyGroupEvents.EMPTY, SignalServiceMessageSender.SenderKeyGroupEvents.EMPTY,
urgent); urgent,
false);
synchronized (entryId) { synchronized (entryId) {
if (entryId.get() == -1) { if (entryId.get() == -1) {
final var newId = messageSendLogStore.insertIfPossible(message.getTimestamp(), final var newId = messageSendLogStore.insertIfPossible(message.getTimestamp(),

View file

@ -1297,11 +1297,31 @@ public class SignalAccount implements Closeable {
return pni; return pni;
} }
public void setPni(final PNI pni) { public void setPni(final PNI updatedPni) {
this.pni = pni; if (this.pni != null && !this.pni.equals(updatedPni)) {
// Clear data for old PNI
identityKeyStore.deleteIdentity(this.pni);
getPniPreKeyStore().removeAllPreKeys();
getPniSignedPreKeyStore().removeAllSignedPreKeys();
}
this.pni = updatedPni;
save(); save();
} }
public void setPni(
final PNI updatedPni,
final IdentityKeyPair pniIdentityKeyPair,
final SignedPreKeyRecord pniSignedPreKey,
final int localPniRegistrationId
) {
setPni(updatedPni);
setPniIdentityKeyPair(pniIdentityKeyPair);
addPniSignedPreKey(pniSignedPreKey);
setLocalPniRegistrationId(localPniRegistrationId);
}
public SignalServiceAddress getSelfAddress() { public SignalServiceAddress getSelfAddress() {
return new SignalServiceAddress(aci, number); return new SignalServiceAddress(aci, number);
} }
@ -1359,6 +1379,11 @@ public class SignalAccount implements Closeable {
return localPniRegistrationId; return localPniRegistrationId;
} }
public void setLocalPniRegistrationId(final int localPniRegistrationId) {
this.localPniRegistrationId = localPniRegistrationId;
save();
}
public String getPassword() { public String getPassword() {
return password; return password;
} }

View file

@ -19,7 +19,7 @@ public class MessageCacheUtils {
try (var f = new FileInputStream(file)) { try (var f = new FileInputStream(file)) {
var in = new DataInputStream(f); var in = new DataInputStream(f);
var version = in.readInt(); var version = in.readInt();
if (version > 7) { if (version > 8) {
// Unsupported envelope version // Unsupported envelope version
return null; return null;
} }
@ -71,6 +71,10 @@ public class MessageCacheUtils {
if (version >= 7) { if (version >= 7) {
isStory = in.readBoolean(); isStory = in.readBoolean();
} }
String updatedPni = null;
if (version >= 8) {
updatedPni = in.readUTF();
}
Optional<SignalServiceAddress> addressOptional = sourceServiceId == null Optional<SignalServiceAddress> addressOptional = sourceServiceId == null
? Optional.empty() ? Optional.empty()
: Optional.of(new SignalServiceAddress(sourceServiceId, source)); : Optional.of(new SignalServiceAddress(sourceServiceId, source));
@ -84,6 +88,7 @@ public class MessageCacheUtils {
uuid, uuid,
destinationUuid == null ? UuidUtil.UNKNOWN_UUID.toString() : destinationUuid, destinationUuid == null ? UuidUtil.UNKNOWN_UUID.toString() : destinationUuid,
isUrgent, isUrgent,
updatedPni == null ? "" : updatedPni,
isStory); isStory);
} }
} }
@ -91,7 +96,7 @@ public class MessageCacheUtils {
public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException { public static void storeEnvelope(SignalServiceEnvelope envelope, File file) throws IOException {
try (var f = new FileOutputStream(file)) { try (var f = new FileOutputStream(file)) {
try (var out = new DataOutputStream(f)) { try (var out = new DataOutputStream(f)) {
out.writeInt(7); // version out.writeInt(8); // version
out.writeInt(envelope.getType()); out.writeInt(envelope.getType());
out.writeUTF(""); // legacy number out.writeUTF(""); // legacy number
out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : ""); out.writeUTF(envelope.getSourceUuid().isPresent() ? envelope.getSourceUuid().get() : "");
@ -111,6 +116,7 @@ public class MessageCacheUtils {
out.writeLong(envelope.getServerDeliveredTimestamp()); out.writeLong(envelope.getServerDeliveredTimestamp());
out.writeBoolean(envelope.isUrgent()); out.writeBoolean(envelope.isUrgent());
out.writeBoolean(envelope.isStory()); out.writeBoolean(envelope.isStory());
out.writeUTF(envelope.getUpdatedPni() == null ? "" : envelope.getUpdatedPni());
} }
} }
} }