1 package org
.asamk
.signal
.manager
.util
;
3 import org
.asamk
.signal
.manager
.storage
.recipients
.Profile
;
4 import org
.signal
.zkgroup
.profiles
.ProfileKey
;
5 import org
.whispersystems
.libsignal
.util
.Pair
;
6 import org
.whispersystems
.signalservice
.api
.crypto
.InvalidCiphertextException
;
7 import org
.whispersystems
.signalservice
.api
.crypto
.ProfileCipher
;
8 import org
.whispersystems
.signalservice
.api
.profiles
.SignalServiceProfile
;
10 import java
.util
.Base64
;
11 import java
.util
.HashSet
;
13 public class ProfileUtils
{
15 public static Profile
decryptProfile(
16 final ProfileKey profileKey
, final SignalServiceProfile encryptedProfile
18 var profileCipher
= new ProfileCipher(profileKey
);
20 var name
= decrypt(encryptedProfile
.getName(), profileCipher
);
21 var about
= decrypt(encryptedProfile
.getAbout(), profileCipher
);
22 var aboutEmoji
= decrypt(encryptedProfile
.getAboutEmoji(), profileCipher
);
24 final var nameParts
= splitName(name
);
25 return new Profile(System
.currentTimeMillis(),
30 getUnidentifiedAccessMode(encryptedProfile
, profileCipher
),
31 getCapabilities(encryptedProfile
));
32 } catch (InvalidCiphertextException e
) {
37 public static Profile
.UnidentifiedAccessMode
getUnidentifiedAccessMode(
38 final SignalServiceProfile encryptedProfile
, final ProfileCipher profileCipher
40 if (encryptedProfile
.isUnrestrictedUnidentifiedAccess()) {
41 return Profile
.UnidentifiedAccessMode
.UNRESTRICTED
;
44 if (encryptedProfile
.getUnidentifiedAccess() != null && profileCipher
!= null) {
45 final var unidentifiedAccessVerifier
= Base64
.getDecoder().decode(encryptedProfile
.getUnidentifiedAccess());
46 if (profileCipher
.verifyUnidentifiedAccess(unidentifiedAccessVerifier
)) {
47 return Profile
.UnidentifiedAccessMode
.ENABLED
;
51 return Profile
.UnidentifiedAccessMode
.DISABLED
;
54 public static HashSet
<Profile
.Capability
> getCapabilities(final SignalServiceProfile encryptedProfile
) {
55 final var capabilities
= new HashSet
<Profile
.Capability
>();
56 if (encryptedProfile
.getCapabilities().isGv1Migration()) {
57 capabilities
.add(Profile
.Capability
.gv1Migration
);
59 if (encryptedProfile
.getCapabilities().isGv2()) {
60 capabilities
.add(Profile
.Capability
.gv2
);
62 if (encryptedProfile
.getCapabilities().isStorage()) {
63 capabilities
.add(Profile
.Capability
.storage
);
68 private static String
decrypt(
69 final String encryptedName
, final ProfileCipher profileCipher
70 ) throws InvalidCiphertextException
{
72 return encryptedName
== null
74 : new String(profileCipher
.decrypt(Base64
.getDecoder().decode(encryptedName
)));
75 } catch (IllegalArgumentException e
) {
80 private static Pair
<String
, String
> splitName(String name
) {
82 return new Pair
<>(null, null);
84 String
[] parts
= name
.split("\0");
86 switch (parts
.length
) {
88 return new Pair
<>(null, null);
90 return new Pair
<>(parts
[0], null);
92 return new Pair
<>(parts
[0], parts
[1]);