]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/util/ProfileUtils.java
Refactor sticker store
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / util / ProfileUtils.java
1 package org.asamk.signal.manager.util;
2
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;
9
10 import java.util.Base64;
11 import java.util.Date;
12 import java.util.HashSet;
13
14 public class ProfileUtils {
15
16 public static Profile decryptProfile(
17 final ProfileKey profileKey, final SignalServiceProfile encryptedProfile
18 ) {
19 var profileCipher = new ProfileCipher(profileKey);
20 try {
21 var name = decryptName(encryptedProfile.getName(), profileCipher);
22 var about = decryptName(encryptedProfile.getAbout(), profileCipher);
23 var aboutEmoji = decryptName(encryptedProfile.getAboutEmoji(), profileCipher);
24 String unidentifiedAccess;
25 try {
26 unidentifiedAccess = encryptedProfile.getUnidentifiedAccess() == null
27 || !profileCipher.verifyUnidentifiedAccess(Base64.getDecoder()
28 .decode(encryptedProfile.getUnidentifiedAccess()))
29 ? null
30 : encryptedProfile.getUnidentifiedAccess();
31 } catch (IllegalArgumentException e) {
32 unidentifiedAccess = null;
33 }
34 final var nameParts = splitName(name);
35 final var capabilities = new HashSet<Profile.Capability>();
36 if (encryptedProfile.getCapabilities().isGv1Migration()) {
37 capabilities.add(Profile.Capability.gv1Migration);
38 }
39 if (encryptedProfile.getCapabilities().isGv2()) {
40 capabilities.add(Profile.Capability.gv2);
41 }
42 if (encryptedProfile.getCapabilities().isStorage()) {
43 capabilities.add(Profile.Capability.storage);
44 }
45 return new Profile(new Date().getTime(),
46 nameParts.first(),
47 nameParts.second(),
48 about,
49 aboutEmoji,
50 encryptedProfile.isUnrestrictedUnidentifiedAccess()
51 ? Profile.UnidentifiedAccessMode.UNRESTRICTED
52 : unidentifiedAccess != null
53 ? Profile.UnidentifiedAccessMode.ENABLED
54 : Profile.UnidentifiedAccessMode.DISABLED,
55 capabilities);
56 } catch (InvalidCiphertextException e) {
57 return null;
58 }
59 }
60
61 private static String decryptName(
62 final String encryptedName, final ProfileCipher profileCipher
63 ) throws InvalidCiphertextException {
64 try {
65 return encryptedName == null
66 ? null
67 : new String(profileCipher.decryptName(Base64.getDecoder().decode(encryptedName)));
68 } catch (IllegalArgumentException e) {
69 return null;
70 }
71 }
72
73 private static Pair<String, String> splitName(String name) {
74 String[] parts = name.split("\0");
75
76 switch (parts.length) {
77 case 0:
78 return new Pair<>(null, null);
79 case 1:
80 return new Pair<>(parts[0], null);
81 default:
82 return new Pair<>(parts[0], parts[1]);
83 }
84 }
85 }