]> nmode's Git Repositories - signal-cli/blobdiff - lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java
Update libsignal-service
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / util / ProfileUtils.java
index 5d61cab3b2f0ccd81e7b68863967e33e63e6c684..0b5b418a95bf0746f7309c242d52ae23324192bb 100644 (file)
@@ -1,9 +1,8 @@
 package org.asamk.signal.manager.util;
 
-import com.google.protobuf.InvalidProtocolBufferException;
-
 import org.asamk.signal.manager.api.Pair;
-import org.asamk.signal.manager.storage.recipients.Profile;
+import org.asamk.signal.manager.api.PhoneNumberSharingMode;
+import org.asamk.signal.manager.api.Profile;
 import org.signal.libsignal.protocol.IdentityKey;
 import org.signal.libsignal.protocol.InvalidKeyException;
 import org.signal.libsignal.protocol.ecc.ECPublicKey;
@@ -13,19 +12,18 @@ import org.slf4j.LoggerFactory;
 import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
 import org.whispersystems.signalservice.api.crypto.ProfileCipher;
 import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
-import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
+import org.whispersystems.signalservice.internal.push.PaymentAddress;
 
 import java.io.IOException;
 import java.util.Base64;
 import java.util.HashSet;
+import java.util.Optional;
 
 public class ProfileUtils {
 
-    private final static Logger logger = LoggerFactory.getLogger(ProfileUtils.class);
+    private static final Logger logger = LoggerFactory.getLogger(ProfileUtils.class);
 
-    public static Profile decryptProfile(
-            final ProfileKey profileKey, final SignalServiceProfile encryptedProfile
-    ) {
+    public static Profile decryptProfile(final ProfileKey profileKey, final SignalServiceProfile encryptedProfile) {
         var profileCipher = new ProfileCipher(profileKey);
         IdentityKey identityKey = null;
         try {
@@ -35,11 +33,14 @@ public class ProfileUtils {
         }
 
         try {
-            var name = decrypt(encryptedProfile.getName(), profileCipher);
-            var about = trimZeros(decrypt(encryptedProfile.getAbout(), profileCipher));
-            var aboutEmoji = trimZeros(decrypt(encryptedProfile.getAboutEmoji(), profileCipher));
+            var name = decryptString(encryptedProfile.getName(), profileCipher);
+            var about = decryptString(encryptedProfile.getAbout(), profileCipher);
+            var aboutEmoji = decryptString(encryptedProfile.getAboutEmoji(), profileCipher);
 
             final var nameParts = splitName(name);
+            final var remotePhoneNumberSharing = decryptBoolean(encryptedProfile.getPhoneNumberSharing(),
+                    profileCipher).map(v -> v ? PhoneNumberSharingMode.EVERYBODY : PhoneNumberSharingMode.NOBODY)
+                    .orElse(null);
             return new Profile(System.currentTimeMillis(),
                     nameParts.first(),
                     nameParts.second(),
@@ -52,7 +53,8 @@ public class ProfileUtils {
                                     profileCipher,
                                     identityKey.getPublicKey()),
                     getUnidentifiedAccessMode(encryptedProfile, profileCipher),
-                    getCapabilities(encryptedProfile));
+                    getCapabilities(encryptedProfile),
+                    remotePhoneNumberSharing);
         } catch (InvalidCiphertextException e) {
             logger.debug("Failed to decrypt profile for {}", encryptedProfile.getServiceId(), e);
             return null;
@@ -60,7 +62,8 @@ public class ProfileUtils {
     }
 
     public static Profile.UnidentifiedAccessMode getUnidentifiedAccessMode(
-            final SignalServiceProfile encryptedProfile, final ProfileCipher profileCipher
+            final SignalServiceProfile encryptedProfile,
+            final ProfileCipher profileCipher
     ) {
         if (encryptedProfile.isUnrestrictedUnidentifiedAccess()) {
             return Profile.UnidentifiedAccessMode.UNRESTRICTED;
@@ -78,36 +81,44 @@ public class ProfileUtils {
 
     public static HashSet<Profile.Capability> getCapabilities(final SignalServiceProfile encryptedProfile) {
         final var capabilities = new HashSet<Profile.Capability>();
-        if (encryptedProfile.getCapabilities().isGv1Migration()) {
-            capabilities.add(Profile.Capability.gv1Migration);
-        }
         if (encryptedProfile.getCapabilities().isStorage()) {
             capabilities.add(Profile.Capability.storage);
         }
-        if (encryptedProfile.getCapabilities().isSenderKey()) {
-            capabilities.add(Profile.Capability.senderKey);
-        }
-        if (encryptedProfile.getCapabilities().isAnnouncementGroup()) {
-            capabilities.add(Profile.Capability.announcementGroup);
+        if (encryptedProfile.getCapabilities().isStorageServiceEncryptionV2()) {
+            capabilities.add(Profile.Capability.storageServiceEncryptionV2Capability);
         }
 
         return capabilities;
     }
 
-    private static String decrypt(
-            final String encryptedName, final ProfileCipher profileCipher
+    private static String decryptString(
+            final String encrypted,
+            final ProfileCipher profileCipher
     ) throws InvalidCiphertextException {
         try {
-            return encryptedName == null
-                    ? null
-                    : new String(profileCipher.decrypt(Base64.getDecoder().decode(encryptedName)));
+            return encrypted == null ? null : profileCipher.decryptString(Base64.getDecoder().decode(encrypted));
         } catch (IllegalArgumentException e) {
             return null;
         }
     }
 
+    private static Optional<Boolean> decryptBoolean(
+            final String encrypted,
+            final ProfileCipher profileCipher
+    ) throws InvalidCiphertextException {
+        try {
+            return encrypted == null
+                    ? Optional.empty()
+                    : profileCipher.decryptBoolean(Base64.getDecoder().decode(encrypted));
+        } catch (IllegalArgumentException e) {
+            return Optional.empty();
+        }
+    }
+
     private static byte[] decryptAndVerifyMobileCoinAddress(
-            final byte[] encryptedPaymentAddress, final ProfileCipher profileCipher, final ECPublicKey publicKey
+            final byte[] encryptedPaymentAddress,
+            final ProfileCipher profileCipher,
+            final ECPublicKey publicKey
     ) throws InvalidCiphertextException {
         byte[] decrypted;
         try {
@@ -117,10 +128,10 @@ public class ProfileUtils {
             return null;
         }
 
-        SignalServiceProtos.PaymentAddress paymentAddress;
+        PaymentAddress paymentAddress;
         try {
-            paymentAddress = SignalServiceProtos.PaymentAddress.parseFrom(decrypted);
-        } catch (InvalidProtocolBufferException e) {
+            paymentAddress = PaymentAddress.ADAPTER.decode(decrypted);
+        } catch (IOException e) {
             logger.debug("Failed to parse payment address", e);
             return null;
         }
@@ -140,13 +151,4 @@ public class ProfileUtils {
             default -> new Pair<>(parts[0], parts[1]);
         };
     }
-
-    static String trimZeros(String str) {
-        if (str == null) {
-            return null;
-        }
-
-        int pos = str.indexOf(0);
-        return pos == -1 ? str : str.substring(0, pos);
-    }
 }