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,
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,

View file

@ -183,15 +183,15 @@ public class RegistrationManager implements Closeable {
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;

View file

@ -33,6 +33,7 @@ import java.util.Base64;
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;
@ -110,6 +111,17 @@ public final class ProfileHelper {
*/
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);
@ -127,10 +139,11 @@ public final class ProfileHelper {
}
var newProfile = builder.build();
if (uploadProfile) {
try (final var streamDetails = avatar == null
? avatarStore.retrieveProfileAvatar(account.getSelfAddress())
: avatar.isPresent() ? Utils.createStreamDetailsFromFile(avatar.get()) : null) {
dependencies.getAccountManager()
final var avatarPath = dependencies.getAccountManager()
.setVersionedProfile(account.getUuid(),
account.getProfileKey(),
newProfile.getInternalServiceName(),
@ -139,6 +152,9 @@ public final class ProfileHelper {
Optional.absent(),
streamDetails,
List.of(/* TODO */));
builder.withAvatarUrlPath(avatarPath.orNull());
newProfile = builder.build();
}
}
if (avatar != null) {
@ -197,6 +213,7 @@ public final class ProfileHelper {
null,
null,
null,
null,
ProfileUtils.getUnidentifiedAccessMode(encryptedProfile, null),
ProfileUtils.getCapabilities(encryptedProfile));
}
@ -242,15 +259,23 @@ public final class ProfileHelper {
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 {
@ -310,6 +335,15 @@ public final class ProfileHelper {
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));

View file

@ -32,13 +32,18 @@ public class StorageHelper {
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 {
@ -199,12 +204,26 @@ public class StorageHelper {
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 {

View file

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

View file

@ -17,6 +17,8 @@ public class Profile {
private final String aboutEmoji;
private final String avatarUrlPath;
private final UnidentifiedAccessMode unidentifiedAccessMode;
private final Set<Capability> capabilities;
@ -27,6 +29,7 @@ public class Profile {
final String familyName,
final String about,
final String aboutEmoji,
final String avatarUrlPath,
final UnidentifiedAccessMode unidentifiedAccessMode,
final Set<Capability> capabilities
) {
@ -35,6 +38,7 @@ public class Profile {
this.familyName = familyName;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.avatarUrlPath = avatarUrlPath;
this.unidentifiedAccessMode = unidentifiedAccessMode;
this.capabilities = capabilities;
}
@ -45,6 +49,7 @@ public class Profile {
familyName = builder.familyName;
about = builder.about;
aboutEmoji = builder.aboutEmoji;
avatarUrlPath = builder.avatarUrlPath;
unidentifiedAccessMode = builder.unidentifiedAccessMode;
capabilities = builder.capabilities;
}
@ -60,6 +65,7 @@ public class Profile {
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;
@ -107,6 +113,10 @@ public class Profile {
return aboutEmoji;
}
public String getAvatarUrlPath() {
return avatarUrlPath;
}
public UnidentifiedAccessMode getUnidentifiedAccessMode() {
return unidentifiedAccessMode;
}
@ -152,6 +162,7 @@ public class Profile {
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;
@ -179,6 +190,11 @@ public class Profile {
return this;
}
public Builder withAvatarUrlPath(final String val) {
avatarUrlPath = val;
return this;
}
public Builder withUnidentifiedAccessMode(final UnidentifiedAccessMode val) {
unidentifiedAccessMode = val;
return this;

View file

@ -89,6 +89,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
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)
@ -445,6 +446,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
recipient.getProfile().getFamilyName(),
recipient.getProfile().getAbout(),
recipient.getProfile().getAboutEmoji(),
recipient.getProfile().getAvatarUrlPath(),
recipient.getProfile().getUnidentifiedAccessMode().name(),
recipient.getProfile()
.getCapabilities()
@ -558,6 +560,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
public String familyName;
public String about;
public String aboutEmoji;
public String avatarUrlPath;
public String unidentifiedAccessMode;
public Set<String> capabilities;
@ -571,6 +574,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
final String familyName,
final String about,
final String aboutEmoji,
final String avatarUrlPath,
final String unidentifiedAccessMode,
final Set<String> capabilities
) {
@ -579,6 +583,7 @@ public class RecipientStore implements RecipientResolver, ContactsStore, Profile
this.familyName = familyName;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.avatarUrlPath = avatarUrlPath;
this.unidentifiedAccessMode = unidentifiedAccessMode;
this.capabilities = capabilities;
}

View file

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