]> nmode's Git Repositories - signal-cli/commitdiff
Handle PniChangeNumber
authorAsamK <asamk@gmx.de>
Sun, 16 Oct 2022 18:07:33 +0000 (20:07 +0200)
committerAsamK <asamk@gmx.de>
Sun, 16 Oct 2022 18:07:33 +0000 (20:07 +0200)
lib/build.gradle.kts
lib/src/main/java/org/asamk/signal/manager/helper/AccountHelper.java
lib/src/main/java/org/asamk/signal/manager/helper/GroupV2Helper.java
lib/src/main/java/org/asamk/signal/manager/helper/IncomingMessageHandler.java
lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java
lib/src/main/java/org/asamk/signal/manager/util/MessageCacheUtils.java

index ae431ffbdd3a4896295c2408f6cbb57bf282b0e4..1e24d6c714195b7844fb886c0364f9501303f1c3 100644 (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")
index 0b19a69153d33eaf9e3bb2b6bf5d294a1fb4e691..7ae9aa450d0e35897e58e550e91a098b1e72fcfc 100644 (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 {
index 09e3ff955aa78efada8b09c0ec42a07040382186..84747e9c3dc48f2a93e86e7494103c01de4ab862 100644 (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);
index a9c8fdae30c6abb0f31c6aac87f71fca0efbe95c..69ad65f7bfa74459c189416003c4c49c0a156fe2 100644 (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;
     }
 
index e8b19356e1007a63dfb9680263685832c85222de..6d2021e06f541273239df0decb326137b6ad927b 100644 (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(),
index 85e5cadd032ed8859536fe5f0c81324f1bebdc6f..730fe85ac95726628dbc4b528c11459cd8c5b7b5 100644 (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;
     }
index 7e8ebea5304420f468a76d78883c08161efcddfa..f61ed2a2123b583f95dad783ea730e89ac33f67c 100644 (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());
             }
         }
     }