import org.asamk.signal.manager.api.Profile;
import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.internal.SignalDependencies;
+import org.asamk.signal.manager.jobs.SyncStorageJob;
import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.storage.groups.GroupInfoV2;
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.asamk.signal.manager.util.PaymentUtils;
import org.asamk.signal.manager.util.ProfileUtils;
import org.asamk.signal.manager.util.Utils;
+import org.jetbrains.annotations.Nullable;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
+import org.whispersystems.signalservice.api.NetworkResultUtil;
+import org.whispersystems.signalservice.api.crypto.SealedSenderAccess;
import org.whispersystems.signalservice.api.profiles.AvatarUploadParams;
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
account.setProfileKey(profileKey);
context.getAccountHelper().updateAccountAttributes();
setProfile(true, true, null, null, null, null, null, null);
- // TODO update profile key in storage
+ account.getRecipientStore().rotateSelfStorageId();
+ context.getJobExecutor().enqueueJob(new SyncStorageJob());
final var recipientIds = account.getRecipientStore().getRecipientIdsWithEnabledProfileSharing();
for (final var recipientId : recipientIds) {
final var activeGroupIds = account.getGroupStore()
.getGroups()
.stream()
- .filter(g -> g instanceof GroupInfoV2 && g.isMember(selfRecipientId))
+ .filter(g -> g instanceof GroupInfoV2 && g.isMember(selfRecipientId) && g.isProfileSharingEnabled())
.map(g -> (GroupInfoV2) g)
.map(GroupInfoV2::getGroupId)
.toList();
: avatar == null ? AvatarUploadParams.unchanged(true) : AvatarUploadParams.unchanged(false);
final var paymentsAddress = Optional.ofNullable(newProfile.getMobileCoinAddress())
.map(address -> PaymentUtils.signPaymentsAddress(address,
- account.getAciIdentityKeyPair().getPrivateKey()));
+ account.getAciIdentityKeyPair().getPrivateKey()))
+ .orElse(null);
logger.debug("Uploading new profile");
- final var avatarPath = dependencies.getAccountManager()
+ final var avatarPath = NetworkResultUtil.toSetProfileLegacy(dependencies.getProfileApi()
.setVersionedProfile(account.getAci(),
account.getProfileKey(),
newProfile.getInternalServiceName(),
avatarUploadParams,
List.of(/* TODO implement support for badges */),
account.getConfigurationStore().getPhoneNumberSharingMode()
- == PhoneNumberSharingMode.EVERYBODY);
+ == PhoneNumberSharingMode.EVERYBODY));
if (!avatarUploadParams.keepTheSame) {
- builder.withAvatarUrlPath(avatarPath.orElse(null));
+ builder.withAvatarUrlPath(avatarPath);
}
newProfile = builder.build();
}
}
private Profile decryptProfileAndDownloadAvatar(
- final RecipientId recipientId, final ProfileKey profileKey, final SignalServiceProfile encryptedProfile
+ final RecipientId recipientId,
+ final ProfileKey profileKey,
+ final SignalServiceProfile encryptedProfile
) {
final var avatarPath = encryptedProfile.getAvatar();
downloadProfileAvatar(recipientId, avatarPath, profileKey);
}
public void downloadProfileAvatar(
- final RecipientId recipientId, final String avatarPath, final ProfileKey profileKey
+ final RecipientId recipientId,
+ final String avatarPath,
+ final ProfileKey profileKey
) {
var profile = account.getProfileStore().getProfile(recipientId);
if (profile == null || !Objects.equals(avatarPath, profile.getAvatarUrlPath())) {
}
private Single<ProfileAndCredential> retrieveProfile(
- RecipientId recipientId, SignalServiceProfile.RequestType requestType
+ RecipientId recipientId,
+ SignalServiceProfile.RequestType requestType
) {
var unidentifiedAccess = getUnidentifiedAccess(recipientId);
var profileKey = Optional.ofNullable(account.getProfileStore().getProfileKey(recipientId));
.build();
}
+ if (recipientId.equals(account.getSelfRecipientId())) {
+ final var isUnrestricted = encryptedProfile.isUnrestrictedUnidentifiedAccess();
+ if (account.isUnrestrictedUnidentifiedAccess() != isUnrestricted) {
+ account.setUnrestrictedUnidentifiedAccess(isUnrestricted);
+ }
+ if (account.isPrimaryDevice() && profile != null && newProfile.getCapabilities()
+ .contains(Profile.Capability.storageServiceEncryptionV2Capability) && !profile.getCapabilities()
+ .contains(Profile.Capability.storageServiceEncryptionV2Capability)) {
+ context.getJobExecutor().enqueueJob(new SyncStorageJob(true));
+ }
+ }
+
try {
logger.trace("Storing identity");
final var identityKey = new IdentityKey(Base64.getDecoder().decode(encryptedProfile.getIdentityKey()));
logger.trace("Storing profile");
account.getProfileStore().storeProfile(recipientId, newProfile);
+ account.getRecipientStore().markRegistered(recipientId, true);
logger.trace("Done handling retrieved profile");
}).doOnError(e -> {
.withUnidentifiedAccessMode(Profile.UnidentifiedAccessMode.UNKNOWN)
.withCapabilities(Set.of())
.build();
+ if (e instanceof NotFoundException) {
+ logger.debug("Marking recipient {} as unregistered after 404 profile fetch.", recipientId);
+ account.getRecipientStore().markRegistered(recipientId, false);
+ }
account.getProfileStore().storeProfile(recipientId, newProfile);
});
private Single<ProfileAndCredential> retrieveProfile(
SignalServiceAddress address,
Optional<ProfileKey> profileKey,
- Optional<UnidentifiedAccess> unidentifiedAccess,
+ @Nullable SealedSenderAccess unidentifiedAccess,
SignalServiceProfile.RequestType requestType
) {
final var profileService = dependencies.getProfileService();
});
}
- private void downloadProfileAvatar(
- RecipientAddress address, String avatarPath, ProfileKey profileKey
- ) {
+ private void downloadProfileAvatar(RecipientAddress address, String avatarPath, ProfileKey profileKey) {
if (avatarPath == null) {
try {
context.getAvatarStore().deleteProfileAvatar(address);
}
private void retrieveProfileAvatar(
- String avatarPath, ProfileKey profileKey, OutputStream outputStream
+ String avatarPath,
+ ProfileKey profileKey,
+ OutputStream outputStream
) throws IOException {
var tmpFile = IOUtils.createTempFile();
try (var input = dependencies.getMessageReceiver()
}
}
- private Optional<UnidentifiedAccess> getUnidentifiedAccess(RecipientId recipientId) {
- var unidentifiedAccess = context.getUnidentifiedAccessHelper().getAccessFor(recipientId, true);
-
- if (unidentifiedAccess.isPresent()) {
- return unidentifiedAccess.get().getTargetUnidentifiedAccess();
- }
-
- return Optional.empty();
+ private @Nullable SealedSenderAccess getUnidentifiedAccess(RecipientId recipientId) {
+ return context.getUnidentifiedAccessHelper().getSealedSenderAccessFor(recipientId, true);
}
}