avatarStore,
this::resolveSignalServiceAddress,
account.getRecipientStore());
- this.storageHelper = new StorageHelper(account, dependencies, groupHelper);
+ this.storageHelper = new StorageHelper(account, dependencies, groupHelper, profileHelper);
this.contactHelper = new ContactHelper(account);
this.syncHelper = new SyncHelper(account,
attachmentHelper,
account = null;
m.refreshPreKeys();
+ if (response.isStorageCapable()) {
+ m.retrieveRemoteStorage();
+ }
// Set an initial empty profile so user can be added to groups
try {
m.setProfile(null, null, null, null, null);
} catch (NoClassDefFoundError e) {
logger.warn("Failed to set default profile: {}", e.getMessage());
}
- if (response.isStorageCapable()) {
- m.retrieveRemoteStorage();
- }
final var result = m;
m = null;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import io.reactivex.rxjava3.core.Single;
*/
public void setProfile(
String givenName, final String familyName, String about, String aboutEmoji, Optional<File> avatar
+ ) throws IOException {
+ setProfile(true, givenName, familyName, about, aboutEmoji, avatar);
+ }
+
+ public void setProfile(
+ boolean uploadProfile,
+ String givenName,
+ final String familyName,
+ String about,
+ String aboutEmoji,
+ Optional<File> avatar
) throws IOException {
var profile = getRecipientProfile(account.getSelfRecipientId());
var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile);
}
var newProfile = builder.build();
- try (final var streamDetails = avatar == null
- ? avatarStore.retrieveProfileAvatar(account.getSelfAddress())
- : avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) {
- dependencies.getAccountManager()
- .setVersionedProfile(account.getUuid(),
- account.getProfileKey(),
- newProfile.getInternalServiceName(),
- newProfile.getAbout() == null ? "" : newProfile.getAbout(),
- newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(),
- Optional.absent(),
- streamDetails,
- List.of(/* TODO */));
+ if (uploadProfile) {
+ try (final var streamDetails = avatar == null
+ ? avatarStore.retrieveProfileAvatar(account.getSelfAddress())
+ : avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) {
+ final var avatarPath = dependencies.getAccountManager()
+ .setVersionedProfile(account.getUuid(),
+ account.getProfileKey(),
+ newProfile.getInternalServiceName(),
+ newProfile.getAbout() == null ? "" : newProfile.getAbout(),
+ newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(),
+ Optional.absent(),
+ streamDetails,
+ List.of(/* TODO */));
+ builder.withAvatarUrlPath(avatarPath.orNull());
+ newProfile = builder.build();
+ }
}
if (avatar != null) {
null,
null,
null,
+ null,
ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null),
ProfileUtils.getCapabilities(encryptedProfile));
}
private Profile decryptProfileAndDownloadAvatar(
final RecipientId recipientId, final ProfileKey profileKey, final SignalServiceProfile encryptedProfile
) {
- if (encryptedProfile.getAvatar() != null) {
- downloadProfileAvatar(addressResolver.resolveSignalServiceAddress(recipientId),
- encryptedProfile.getAvatar(),
- profileKey);
- }
+ final var avatarPath = encryptedProfile.getAvatar();
+ downloadProfileAvatar(recipientId, avatarPath, profileKey);
return ProfileUtils.decryptProfile(profileKey, encryptedProfile);
}
+ public void downloadProfileAvatar(
+ final RecipientId recipientId, final String avatarPath, final ProfileKey profileKey
+ ) {
+ var profile = account.getProfileStore().getProfile(recipientId);
+ if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) {
+ downloadProfileAvatar(addressResolver.resolveSignalServiceAddress(recipientId), avatarPath, profileKey);
+ var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile);
+ account.getProfileStore().storeProfile(recipientId, builder.withAvatarUrlPath(avatarPath).build());
+ }
+ }
+
private ProfileAndCredential retrieveProfileSync(
RecipientId recipientId, SignalServiceProfile.RequestType requestType
) throws IOException {
private void downloadProfileAvatar(
SignalServiceAddress address, String avatarPath, ProfileKey profileKey
) {
+ if (avatarPath == null) {
+ try {
+ avatarStore.deleteProfileAvatar(address);
+ } catch (IOException e) {
+ logger.warn("Failed to delete local profile avatar, ignoring: {}", e.getMessage());
+ }
+ return;
+ }
+
try {
avatarStore.storeProfileAvatar(address,
outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream));
private final SignalAccount account;
private final SignalDependencies dependencies;
private final GroupHelper groupHelper;
+ private final ProfileHelper profileHelper;
public StorageHelper(
- final SignalAccount account, final SignalDependencies dependencies, final GroupHelper groupHelper
+ final SignalAccount account,
+ final SignalDependencies dependencies,
+ final GroupHelper groupHelper,
+ final ProfileHelper profileHelper
) {
this.account = account;
this.dependencies = dependencies;
this.groupHelper = groupHelper;
+ this.profileHelper = profileHelper;
}
public void readDataFromStorage() throws IOException {
account.getConfigurationStore().setLinkPreviews(accountRecord.isLinkPreviewsEnabled());
if (accountRecord.getProfileKey().isPresent()) {
+ ProfileKey profileKey;
try {
- account.setProfileKey(new ProfileKey(accountRecord.getProfileKey().get()));
+ profileKey = new ProfileKey(accountRecord.getProfileKey().get());
} catch (InvalidInputException e) {
logger.warn("Received invalid profile key from storage");
+ profileKey = null;
+ }
+ if (profileKey != null) {
+ account.setProfileKey(profileKey);
+ final var avatarPath = accountRecord.getAvatarUrlPath().orNull();
+ profileHelper.downloadProfileAvatar(account.getSelfRecipientId(), avatarPath, profileKey);
}
}
+
+ profileHelper.setProfile(false,
+ accountRecord.getGivenName().orNull(),
+ accountRecord.getFamilyName().orNull(),
+ null,
+ null,
+ null);
}
private SignalStorageRecord getSignalStorageRecord(final StorageId accountId) throws IOException {
profile.getFamilyName(),
profile.getAbout(),
profile.getAboutEmoji(),
+ null,
profile.isUnrestrictedUnidentifiedAccess()
? Profile.UnidentifiedAccessMode.UNRESTRICTED
: profile.getUnidentifiedAccess() != null
private final String aboutEmoji;
+ private final String avatarUrlPath;
+
private final UnidentifiedAccessMode unidentifiedAccessMode;
private final Set<Capability> capabilities;
final String familyName,
final String about,
final String aboutEmoji,
+ final String avatarUrlPath,
final UnidentifiedAccessMode unidentifiedAccessMode,
final Set<Capability> capabilities
) {
this.familyName = familyName;
this.about = about;
this.aboutEmoji = aboutEmoji;
+ this.avatarUrlPath = avatarUrlPath;
this.unidentifiedAccessMode = unidentifiedAccessMode;
this.capabilities = capabilities;
}
familyName = builder.familyName;
about = builder.about;
aboutEmoji = builder.aboutEmoji;
+ avatarUrlPath = builder.avatarUrlPath;
unidentifiedAccessMode = builder.unidentifiedAccessMode;
capabilities = builder.capabilities;
}
builder.familyName = copy.getFamilyName();
builder.about = copy.getAbout();
builder.aboutEmoji = copy.getAboutEmoji();
+ builder.avatarUrlPath = copy.getAvatarUrlPath();
builder.unidentifiedAccessMode = copy.getUnidentifiedAccessMode();
builder.capabilities = copy.getCapabilities();
return builder;
return aboutEmoji;
}
+ public String getAvatarUrlPath() {
+ return avatarUrlPath;
+ }
+
public UnidentifiedAccessMode getUnidentifiedAccessMode() {
return unidentifiedAccessMode;
}
private String familyName;
private String about;
private String aboutEmoji;
+ private String avatarUrlPath;
private UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN;
private Set<Capability> capabilities = Collections.emptySet();
private long lastUpdateTimestamp = 0;
return this;
}
+ public Builder withAvatarUrlPath(final String val) {
+ avatarUrlPath = val;
+ return this;
+ }
+
public Builder withUnidentifiedAccessMode(final UnidentifiedAccessMode val) {
unidentifiedAccessMode = val;
return this;
r.profile.familyName,
r.profile.about,
r.profile.aboutEmoji,
+ r.profile.avatarUrlPath,
Profile.UnidentifiedAccessMode.valueOfOrUnknown(r.profile.unidentifiedAccessMode),
r.profile.capabilities.stream()
.map(Profile.Capability::valueOfOrNull)
recipient.getProfile().getFamilyName(),
recipient.getProfile().getAbout(),
recipient.getProfile().getAboutEmoji(),
+ recipient.getProfile().getAvatarUrlPath(),
recipient.getProfile().getUnidentifiedAccessMode().name(),
recipient.getProfile()
.getCapabilities()
public String familyName;
public String about;
public String aboutEmoji;
+ public String avatarUrlPath;
public String unidentifiedAccessMode;
public Set<String> capabilities;
final String familyName,
final String about,
final String aboutEmoji,
+ final String avatarUrlPath,
final String unidentifiedAccessMode,
final Set<String> capabilities
) {
this.familyName = familyName;
this.about = about;
this.aboutEmoji = aboutEmoji;
+ this.avatarUrlPath = avatarUrlPath;
this.unidentifiedAccessMode = unidentifiedAccessMode;
this.capabilities = capabilities;
}
nameParts.second(),
about,
aboutEmoji,
+ encryptedProfile.getAvatar(),
getUnidentifiedAccessMode(encryptedProfile, profileCipher),
getCapabilities(encryptedProfile));
} catch (InvalidCiphertextException e) {