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 {
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.google.protobuf", "protobuf-javalite", "3.21.6")
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.util.KeyUtils;
import org.asamk.signal.manager.util.NumberVerificationUtils;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest;
import org.whispersystems.signalservice.api.push.ACI;
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.exceptions.AuthorizationFailedException;
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
@ -111,6 +114,19 @@ public class AccountHelper {
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(
String newNumber, String captcha, boolean voiceVerification
) throws IOException, CaptchaRequiredException, NonNormalizedPhoneNumberException {

View file

@ -77,6 +77,10 @@ class GroupV2Helper {
this.context = context;
}
void clearAuthCredentialCache() {
groupApiCredentials = null;
}
DecryptedGroup getDecryptedGroup(final GroupSecretParams groupSecretParams) throws NotAGroupMemberException {
try {
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.ProtocolUntrustedIdentityException;
import org.signal.libsignal.metadata.SelfSendException;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidMessageException;
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.profiles.ProfileKey;
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.multidevice.SignalServiceSyncMessage;
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.SignalServiceAddress;
@ -304,7 +307,10 @@ public final class IncomingMessageHandler {
if (content.getSyncMessage().isPresent()) {
var syncMessage = content.getSyncMessage().get();
actions.addAll(handleSyncMessage(syncMessage, senderDeviceAddress, receiveConfig.ignoreAttachments()));
actions.addAll(handleSyncMessage(envelope,
syncMessage,
senderDeviceAddress,
receiveConfig.ignoreAttachments()));
}
return actions;
@ -364,7 +370,10 @@ public final class IncomingMessageHandler {
}
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>();
account.setMultiDevice(true);
@ -519,7 +528,26 @@ public final class IncomingMessageHandler {
pniIdentity.getPrivateKey().toByteArray()));
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;
}

View file

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

View file

@ -1297,11 +1297,31 @@ public class SignalAccount implements Closeable {
return pni;
}
public void setPni(final PNI pni) {
this.pni = pni;
public void setPni(final PNI updatedPni) {
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();
}
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() {
return new SignalServiceAddress(aci, number);
}
@ -1359,6 +1379,11 @@ public class SignalAccount implements Closeable {
return localPniRegistrationId;
}
public void setLocalPniRegistrationId(final int localPniRegistrationId) {
this.localPniRegistrationId = localPniRegistrationId;
save();
}
public String getPassword() {
return password;
}

View file

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