+ private SignalProfile getRecipientProfile(
+ SignalServiceAddress address
+ ) {
+ SignalProfileEntry profileEntry = account.getProfileStore().getProfileEntry(address);
+ if (profileEntry == null) {
+ return null;
+ }
+ long now = new Date().getTime();
+ // Profiles are cache for 24h before retrieving them again
+ if (!profileEntry.isRequestPending() && (
+ profileEntry.getProfile() == null || now - profileEntry.getLastUpdateTimestamp() > 24 * 60 * 60 * 1000
+ )) {
+ ProfileKey profileKey = profileEntry.getProfileKey();
+ profileEntry.setRequestPending(true);
+ SignalProfile profile;
+ try {
+ profile = retrieveRecipientProfile(address, profileKey);
+ } catch (IOException e) {
+ logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());
+ profileEntry.setRequestPending(false);
+ return null;
+ }
+ profileEntry.setRequestPending(false);
+ account.getProfileStore()
+ .updateProfile(address, profileKey, now, profile, profileEntry.getProfileKeyCredential());
+ return profile;
+ }
+ return profileEntry.getProfile();
+ }
+
+ private ProfileKeyCredential getRecipientProfileKeyCredential(SignalServiceAddress address) {
+ SignalProfileEntry profileEntry = account.getProfileStore().getProfileEntry(address);
+ if (profileEntry == null) {
+ return null;
+ }
+ if (profileEntry.getProfileKeyCredential() == null) {
+ ProfileAndCredential profileAndCredential;
+ try {
+ profileAndCredential = profileHelper.retrieveProfileSync(address,
+ SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL);
+ } catch (IOException e) {
+ logger.warn("Failed to retrieve profile key credential, ignoring: {}", e.getMessage());
+ return null;
+ }
+
+ long now = new Date().getTime();
+ final ProfileKeyCredential profileKeyCredential = profileAndCredential.getProfileKeyCredential().orNull();
+ final SignalProfile profile = decryptProfile(address,
+ profileEntry.getProfileKey(),
+ profileAndCredential.getProfile());
+ account.getProfileStore()
+ .updateProfile(address, profileEntry.getProfileKey(), now, profile, profileKeyCredential);
+ return profileKeyCredential;
+ }
+ return profileEntry.getProfileKeyCredential();
+ }
+
+ private SignalProfile retrieveRecipientProfile(
+ SignalServiceAddress address, ProfileKey profileKey
+ ) throws IOException {
+ final SignalServiceProfile encryptedProfile = getEncryptedRecipientProfile(address);
+
+ return decryptProfile(address, profileKey, encryptedProfile);
+ }
+
+ private SignalProfile decryptProfile(
+ final SignalServiceAddress address, final ProfileKey profileKey, final SignalServiceProfile encryptedProfile
+ ) {
+ File avatarFile = null;
+ try {
+ avatarFile = encryptedProfile.getAvatar() == null
+ ? null
+ : retrieveProfileAvatar(address, encryptedProfile.getAvatar(), profileKey);
+ } catch (Throwable e) {
+ logger.warn("Failed to retrieve profile avatar, ignoring: {}", e.getMessage());
+ }
+
+ ProfileCipher profileCipher = new ProfileCipher(profileKey);
+ try {
+ String name;
+ try {
+ name = encryptedProfile.getName() == null
+ ? null
+ : new String(profileCipher.decryptName(Base64.decode(encryptedProfile.getName())));
+ } catch (IOException e) {
+ name = null;
+ }
+ String unidentifiedAccess;
+ try {
+ unidentifiedAccess = encryptedProfile.getUnidentifiedAccess() == null
+ || !profileCipher.verifyUnidentifiedAccess(Base64.decode(encryptedProfile.getUnidentifiedAccess()))
+ ? null
+ : encryptedProfile.getUnidentifiedAccess();
+ } catch (IOException e) {
+ unidentifiedAccess = null;
+ }
+ return new SignalProfile(encryptedProfile.getIdentityKey(),
+ name,
+ avatarFile,
+ unidentifiedAccess,
+ encryptedProfile.isUnrestrictedUnidentifiedAccess(),
+ encryptedProfile.getCapabilities());
+ } catch (InvalidCiphertextException e) {
+ return null;
+ }
+ }
+
+ private Optional<SignalServiceAttachmentStream> createGroupAvatarAttachment(GroupId groupId) throws IOException {