Retrieve self profile from storage

This commit is contained in:
AsamK 2021-10-03 16:17:58 +02:00
parent 0709c0caf8
commit 26594dd0ee
8 changed files with 99 additions and 23 deletions

View file

@ -209,7 +209,7 @@ public class ManagerImpl implements Manager {
avatarStore, avatarStore,
this::resolveSignalServiceAddress, this::resolveSignalServiceAddress,
account.getRecipientStore()); account.getRecipientStore());
this.storageHelper = new StorageHelper(account, dependencies, groupHelper); this.storageHelper = new StorageHelper(account, dependencies, groupHelper, profileHelper);
this.contactHelper = new ContactHelper(account); this.contactHelper = new ContactHelper(account);
this.syncHelper = new SyncHelper(account, this.syncHelper = new SyncHelper(account,
attachmentHelper, attachmentHelper,

View file

@ -183,15 +183,15 @@ public class RegistrationManager implements Closeable {
account = null; account = null;
m.refreshPreKeys(); m.refreshPreKeys();
if (response.isStorageCapable()) {
m.retrieveRemoteStorage();
}
// Set an initial empty profile so user can be added to groups // Set an initial empty profile so user can be added to groups
try { try {
m.setProfile(null, null, null, null, null); m.setProfile(null, null, null, null, null);
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
logger.warn("Failed to set default profile: {}", e.getMessage()); logger.warn("Failed to set default profile: {}", e.getMessage());
} }
if (response.isStorageCapable()) {
m.retrieveRemoteStorage();
}
final var result = m; final var result = m;
m = null; m = null;

View file

@ -33,6 +33,7 @@ import java.util.Base64;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
@ -110,6 +111,17 @@ public final class ProfileHelper {
*/ */
public void setProfile( public void setProfile(
String givenName, final String familyName, String about, String aboutEmoji, Optional<File> avatar 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 { ) throws IOException {
var profile = getRecipientProfile(account.getSelfRecipientId()); var profile = getRecipientProfile(account.getSelfRecipientId());
var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile); var builder = profile == null ? Profile.newBuilder() : Profile.newBuilder(profile);
@ -127,18 +139,22 @@ public final class ProfileHelper {
} }
var newProfile = builder.build(); var newProfile = builder.build();
try (final var streamDetails = avatar == null if (uploadProfile) {
? avatarStore.retrieveProfileAvatar(account.getSelfAddress()) try (final var streamDetails = avatar == null
: avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) { ? avatarStore.retrieveProfileAvatar(account.getSelfAddress())
dependencies.getAccountManager() : avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) {
.setVersionedProfile(account.getUuid(), final var avatarPath = dependencies.getAccountManager()
account.getProfileKey(), .setVersionedProfile(account.getUuid(),
newProfile.getInternalServiceName(), account.getProfileKey(),
newProfile.getAbout() == null ? "" : newProfile.getAbout(), newProfile.getInternalServiceName(),
newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(), newProfile.getAbout() == null ? "" : newProfile.getAbout(),
Optional.absent(), newProfile.getAboutEmoji() == null ? "" : newProfile.getAboutEmoji(),
streamDetails, Optional.absent(),
List.of(/* TODO */)); streamDetails,
List.of(/* TODO */));
builder.withAvatarUrlPath(avatarPath.orNull());
newProfile = builder.build();
}
} }
if (avatar != null) { if (avatar != null) {
@ -197,6 +213,7 @@ public final class ProfileHelper {
null, null,
null, null,
null, null,
null,
ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null), ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null),
ProfileUtils.getCapabilities(encryptedProfile)); ProfileUtils.getCapabilities(encryptedProfile));
} }
@ -242,15 +259,23 @@ public final class ProfileHelper {
private Profile decryptProfileAndDownloadAvatar( private Profile decryptProfileAndDownloadAvatar(
final RecipientId recipientId, final ProfileKey profileKey, final SignalServiceProfile encryptedProfile final RecipientId recipientId, final ProfileKey profileKey, final SignalServiceProfile encryptedProfile
) { ) {
if (encryptedProfile.getAvatar() != null) { final var avatarPath = encryptedProfile.getAvatar();
downloadProfileAvatar(addressResolver.resolveSignalServiceAddress(recipientId), downloadProfileAvatar(recipientId, avatarPath, profileKey);
encryptedProfile.getAvatar(),
profileKey);
}
return ProfileUtils.decryptProfile(profileKey, encryptedProfile); 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( private ProfileAndCredential retrieveProfileSync(
RecipientId recipientId, SignalServiceProfile.RequestType requestType RecipientId recipientId, SignalServiceProfile.RequestType requestType
) throws IOException { ) throws IOException {
@ -310,6 +335,15 @@ public final class ProfileHelper {
private void downloadProfileAvatar( private void downloadProfileAvatar(
SignalServiceAddress address, String avatarPath, ProfileKey profileKey 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 { try {
avatarStore.storeProfileAvatar(address, avatarStore.storeProfileAvatar(address,
outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream)); outputStream -> retrieveProfileAvatar(avatarPath, profileKey, outputStream));

View file

@ -32,13 +32,18 @@ public class StorageHelper {
private final SignalAccount account; private final SignalAccount account;
private final SignalDependencies dependencies; private final SignalDependencies dependencies;
private final GroupHelper groupHelper; private final GroupHelper groupHelper;
private final ProfileHelper profileHelper;
public StorageHelper( 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.account = account;
this.dependencies = dependencies; this.dependencies = dependencies;
this.groupHelper = groupHelper; this.groupHelper = groupHelper;
this.profileHelper = profileHelper;
} }
public void readDataFromStorage() throws IOException { public void readDataFromStorage() throws IOException {
@ -199,12 +204,26 @@ public class StorageHelper {
account.getConfigurationStore().setLinkPreviews(accountRecord.isLinkPreviewsEnabled()); account.getConfigurationStore().setLinkPreviews(accountRecord.isLinkPreviewsEnabled());
if (accountRecord.getProfileKey().isPresent()) { if (accountRecord.getProfileKey().isPresent()) {
ProfileKey profileKey;
try { try {
account.setProfileKey(new ProfileKey(accountRecord.getProfileKey().get())); profileKey = new ProfileKey(accountRecord.getProfileKey().get());
} catch (InvalidInputException e) { } catch (InvalidInputException e) {
logger.warn("Received invalid profile key from storage"); 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 { private SignalStorageRecord getSignalStorageRecord(final StorageId accountId) throws IOException {

View file

@ -631,6 +631,7 @@ public class SignalAccount implements Closeable {
profile.getFamilyName(), profile.getFamilyName(),
profile.getAbout(), profile.getAbout(),
profile.getAboutEmoji(), profile.getAboutEmoji(),
null,
profile.isUnrestrictedUnidentifiedAccess() profile.isUnrestrictedUnidentifiedAccess()
? Profile.UnidentifiedAccessMode.UNRESTRICTED ? Profile.UnidentifiedAccessMode.UNRESTRICTED
: profile.getUnidentifiedAccess() != null : profile.getUnidentifiedAccess() != null

View file

@ -17,6 +17,8 @@ public class Profile {
private final String aboutEmoji; private final String aboutEmoji;
private final String avatarUrlPath;
private final UnidentifiedAccessMode unidentifiedAccessMode; private final UnidentifiedAccessMode unidentifiedAccessMode;
private final Set<Capability> capabilities; private final Set<Capability> capabilities;
@ -27,6 +29,7 @@ public class Profile {
final String familyName, final String familyName,
final String about, final String about,
final String aboutEmoji, final String aboutEmoji,
final String avatarUrlPath,
final UnidentifiedAccessMode unidentifiedAccessMode, final UnidentifiedAccessMode unidentifiedAccessMode,
final Set<Capability> capabilities final Set<Capability> capabilities
) { ) {
@ -35,6 +38,7 @@ public class Profile {
this.familyName = familyName; this.familyName = familyName;
this.about = about; this.about = about;
this.aboutEmoji = aboutEmoji; this.aboutEmoji = aboutEmoji;
this.avatarUrlPath = avatarUrlPath;
this.unidentifiedAccessMode = unidentifiedAccessMode; this.unidentifiedAccessMode = unidentifiedAccessMode;
this.capabilities = capabilities; this.capabilities = capabilities;
} }
@ -45,6 +49,7 @@ public class Profile {
familyName = builder.familyName; familyName = builder.familyName;
about = builder.about; about = builder.about;
aboutEmoji = builder.aboutEmoji; aboutEmoji = builder.aboutEmoji;
avatarUrlPath = builder.avatarUrlPath;
unidentifiedAccessMode = builder.unidentifiedAccessMode; unidentifiedAccessMode = builder.unidentifiedAccessMode;
capabilities = builder.capabilities; capabilities = builder.capabilities;
} }
@ -60,6 +65,7 @@ public class Profile {
builder.familyName = copy.getFamilyName(); builder.familyName = copy.getFamilyName();
builder.about = copy.getAbout(); builder.about = copy.getAbout();
builder.aboutEmoji = copy.getAboutEmoji(); builder.aboutEmoji = copy.getAboutEmoji();
builder.avatarUrlPath = copy.getAvatarUrlPath();
builder.unidentifiedAccessMode = copy.getUnidentifiedAccessMode(); builder.unidentifiedAccessMode = copy.getUnidentifiedAccessMode();
builder.capabilities = copy.getCapabilities(); builder.capabilities = copy.getCapabilities();
return builder; return builder;
@ -107,6 +113,10 @@ public class Profile {
return aboutEmoji; return aboutEmoji;
} }
public String getAvatarUrlPath() {
return avatarUrlPath;
}
public UnidentifiedAccessMode getUnidentifiedAccessMode() { public UnidentifiedAccessMode getUnidentifiedAccessMode() {
return unidentifiedAccessMode; return unidentifiedAccessMode;
} }
@ -152,6 +162,7 @@ public class Profile {
private String familyName; private String familyName;
private String about; private String about;
private String aboutEmoji; private String aboutEmoji;
private String avatarUrlPath;
private UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN; private UnidentifiedAccessMode unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN;
private Set<Capability> capabilities = Collections.emptySet(); private Set<Capability> capabilities = Collections.emptySet();
private long lastUpdateTimestamp = 0; private long lastUpdateTimestamp = 0;
@ -179,6 +190,11 @@ public class Profile {
return this; return this;
} }
public Builder withAvatarUrlPath(final String val) {
avatarUrlPath = val;
return this;
}
public Builder withUnidentifiedAccessMode(final UnidentifiedAccessMode val) { public Builder withUnidentifiedAccessMode(final UnidentifiedAccessMode val) {
unidentifiedAccessMode = val; unidentifiedAccessMode = val;
return this; return this;

View file

@ -89,6 +89,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
r.profile.familyName, r.profile.familyName,
r.profile.about, r.profile.about,
r.profile.aboutEmoji, r.profile.aboutEmoji,
r.profile.avatarUrlPath,
Profile.UnidentifiedAccessMode.valueOfOrUnknown(r.profile.unidentifiedAccessMode), Profile.UnidentifiedAccessMode.valueOfOrUnknown(r.profile.unidentifiedAccessMode),
r.profile.capabilities.stream() r.profile.capabilities.stream()
.map(Profile.Capability::valueOfOrNull) .map(Profile.Capability::valueOfOrNull)
@ -445,6 +446,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
recipient.getProfile().getFamilyName(), recipient.getProfile().getFamilyName(),
recipient.getProfile().getAbout(), recipient.getProfile().getAbout(),
recipient.getProfile().getAboutEmoji(), recipient.getProfile().getAboutEmoji(),
recipient.getProfile().getAvatarUrlPath(),
recipient.getProfile().getUnidentifiedAccessMode().name(), recipient.getProfile().getUnidentifiedAccessMode().name(),
recipient.getProfile() recipient.getProfile()
.getCapabilities() .getCapabilities()
@ -558,6 +560,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
public String familyName; public String familyName;
public String about; public String about;
public String aboutEmoji; public String aboutEmoji;
public String avatarUrlPath;
public String unidentifiedAccessMode; public String unidentifiedAccessMode;
public Set<String> capabilities; public Set<String> capabilities;
@ -571,6 +574,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
final String familyName, final String familyName,
final String about, final String about,
final String aboutEmoji, final String aboutEmoji,
final String avatarUrlPath,
final String unidentifiedAccessMode, final String unidentifiedAccessMode,
final Set<String> capabilities final Set<String> capabilities
) { ) {
@ -579,6 +583,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
this.familyName = familyName; this.familyName = familyName;
this.about = about; this.about = about;
this.aboutEmoji = aboutEmoji; this.aboutEmoji = aboutEmoji;
this.avatarUrlPath = avatarUrlPath;
this.unidentifiedAccessMode = unidentifiedAccessMode; this.unidentifiedAccessMode = unidentifiedAccessMode;
this.capabilities = capabilities; this.capabilities = capabilities;
} }

View file

@ -27,6 +27,7 @@ public class ProfileUtils {
nameParts.second(), nameParts.second(),
about, about,
aboutEmoji, aboutEmoji,
encryptedProfile.getAvatar(),
getUnidentifiedAccessMode(encryptedProfile, profileCipher), getUnidentifiedAccessMode(encryptedProfile, profileCipher),
getCapabilities(encryptedProfile)); getCapabilities(encryptedProfile));
} catch (InvalidCiphertextException e) { } catch (InvalidCiphertextException e) {