mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
Retrieve self profile from storage
This commit is contained in:
parent
0709c0caf8
commit
26594dd0ee
8 changed files with 99 additions and 23 deletions
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,18 +139,22 @@ public final class ProfileHelper {
|
|||
}
|
||||
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) {
|
||||
|
@ -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));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -631,6 +631,7 @@ public class SignalAccount implements Closeable {
|
|||
profile.getFamilyName(),
|
||||
profile.getAbout(),
|
||||
profile.getAboutEmoji(),
|
||||
null,
|
||||
profile.isUnrestrictedUnidentifiedAccess()
|
||||
? Profile.UnidentifiedAccessMode.UNRESTRICTED
|
||||
: profile.getUnidentifiedAccess() != null
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ public class ProfileUtils {
|
|||
nameParts.second(),
|
||||
about,
|
||||
aboutEmoji,
|
||||
encryptedProfile.getAvatar(),
|
||||
getUnidentifiedAccessMode(encryptedProfile, profileCipher),
|
||||
getCapabilities(encryptedProfile));
|
||||
} catch (InvalidCiphertextException e) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue