Public chat avatar handling.

Fix note to self.
This commit is contained in:
Mikunj 2019-11-28 12:49:33 +11:00
parent 0cefac1bce
commit 280d866df3
6 changed files with 94 additions and 17 deletions

View File

@ -43,6 +43,8 @@ import org.thoughtcrime.securesms.components.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseContentProviders;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
@ -75,6 +77,7 @@ import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
@ -207,6 +210,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
checkNeedsRevocation();
}
}
updatePublicChatProfileAvatarIfNeeded();
}
@Override
@ -597,6 +601,26 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
if (lokiNewsFeedPoller != null) lokiNewsFeedPoller.startIfNeeded();
if (lokiMessengerUpdatesFeedPoller != null) lokiMessengerUpdatesFeedPoller.startIfNeeded();
}
public void updatePublicChatProfileAvatarIfNeeded() {
AsyncTask.execute(() -> {
LokiPublicChatAPI publicChatAPI = getLokiPublicChatAPI();
if (publicChatAPI != null) {
byte[] profileKey = ProfileKeyUtil.getProfileKey(this);
String url = TextSecurePreferences.getProfileAvatarUrl(this);
String ourMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
if (ourMasterDevice != null) {
Recipient masterDevice = Recipient.from(this, Address.fromSerialized(ourMasterDevice), false).resolve();
profileKey = masterDevice.getProfileKey();
url = masterDevice.getProfileAvatar();
}
Set<String> servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers();
for (String server : servers) {
publicChatAPI.setProfileAvatar(server, profileKey, url);
}
}
});
}
// endregion
public void checkNeedsRevocation() {

View File

@ -67,6 +67,7 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
@ -421,7 +422,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
// Upload was successful with this new profile key, we should set it so the other users know to re-fetch profiles
ProfileKeyUtil.setEncodedProfileKey(context, newProfileKey);
// TODO: Update profile key in public chats here
// Update profile key on the public chat server
ApplicationContext.getInstance(context).updatePublicChatProfileAvatarIfNeeded();
} catch (Exception e) {
Log.d("Loki", "Failed to upload profile photo: " + e);
return false;

View File

@ -120,24 +120,26 @@ public class AvatarImageView extends AppCompatImageView {
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
if (recipient != null) {
RecipientContactPhoto photo = new RecipientContactPhoto(recipient);
if (!photo.equals(recipientContactPhoto)) {
requestManager.clear(this);
recipientContactPhoto = photo;
if (recipient.isLocalNumber()) {
setImageDrawable(new ResourceContactPhoto(R.drawable.ic_note_to_self).asDrawable(getContext(), recipient.getColor().toAvatarColor(getContext()), inverted));
} else {
RecipientContactPhoto photo = new RecipientContactPhoto(recipient);
if (!photo.equals(recipientContactPhoto)) {
requestManager.clear(this);
recipientContactPhoto = photo;
Drawable fallbackContactPhotoDrawable = recipient.isLocalNumber()
? new ResourceContactPhoto(R.drawable.ic_note_to_self).asDrawable(getContext(), recipient.getColor().toAvatarColor(getContext()), inverted)
: photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted);
Drawable fallbackContactPhotoDrawable = photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted);
if (photo.contactPhoto != null) {
requestManager.load(photo.contactPhoto)
.fallback(fallbackContactPhotoDrawable)
.error(fallbackContactPhotoDrawable)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(this);
} else {
setImageDrawable(fallbackContactPhotoDrawable);
if (photo.contactPhoto != null) {
requestManager.load(photo.contactPhoto)
.fallback(fallbackContactPhotoDrawable)
.error(fallbackContactPhotoDrawable)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(this);
} else {
setImageDrawable(fallbackContactPhotoDrawable);
}
}
}
} else {

View File

@ -130,6 +130,7 @@ import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession;
import org.whispersystems.signalservice.loki.api.LokiAPI;
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
import org.whispersystems.signalservice.loki.api.PairingAuthorisation;
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
@ -146,6 +147,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
@ -1442,6 +1444,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
database.setUnidentifiedAccessMode(recipient, RecipientDatabase.UnidentifiedAccessMode.UNKNOWN);
String url = content.senderProfileAvatarUrl.or("");
ApplicationContext.getInstance(context).getJobManager().add(new RetrieveProfileAvatarJob(recipient, url));
// Loki - If the recipient is our master device then we need to go and update our avatar mappings on the public chats
if (recipient.isOurMasterDevice()) {
ApplicationContext.getInstance(context).updatePublicChatProfileAvatarIfNeeded();
}
}
}

View File

@ -54,6 +54,7 @@ class DisplayNameActivity : BaseActionBarActivity() {
application.startRSSFeedPollersIfNeeded()
val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
servers.forEach { publicChatAPI.setDisplayName(name, it) }
application.updatePublicChatProfileAvatarIfNeeded()
}
}
}

View File

@ -6,9 +6,14 @@ import android.util.Log
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.then
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.jobs.PushDecryptJob
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.libsignal.util.guava.Optional
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer
@ -21,7 +26,9 @@ import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI
import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage
import org.whispersystems.signalservice.loki.api.LokiStorageAPI
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.utilities.successBackground
import java.security.MessageDigest
import java.util.*
class LokiPublicChatPoller(private val context: Context, private val group: LokiPublicChat) {
@ -155,6 +162,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName)
}
val senderPublicKey = primaryDevice ?: message.hexEncodedPublicKey
val serviceDataMessage = getDataMessage(message)
val serviceContent = SignalServiceContent(serviceDataMessage, senderPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false)
@ -163,6 +171,25 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
} else {
PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
}
// Update profile avatar if needed
val senderRecipient = Recipient.from(context, Address.fromSerialized(senderPublicKey), false)
if (message.avatar != null && message.avatar!!.url.isNotEmpty()) {
val profileKey = message.avatar!!.profileKey
val url = message.avatar!!.url
if (senderRecipient.profileKey == null || !MessageDigest.isEqual(senderRecipient.profileKey, profileKey)) {
val database = DatabaseFactory.getRecipientDatabase(context)
database.setProfileKey(senderRecipient, profileKey)
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderRecipient, url))
}
} else if (senderRecipient.profileAvatar.orEmpty().isNotEmpty()) {
// Unset the avatar if we had an avatar before and we're not friends with the person
val threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(senderRecipient)
val friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId)
if (friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) {
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderRecipient, ""))
}
}
}
fun processOutgoingMessage(message: LokiPublicChatMessage) {
val messageServerID = message.serverID ?: return
@ -178,6 +205,19 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
} else {
PushDecryptJob(context).handleSynchronizeSentTextMessage(transcript)
}
// Loki - If we got a message from our master device then make sure our mappings stay in sync
val recipient = Recipient.from(context, Address.fromSerialized(message.hexEncodedPublicKey), false)
if (recipient.isOurMasterDevice && message.avatar != null) {
val profileKey = message.avatar!!.profileKey
val url = message.avatar!!.url
if (recipient.profileKey == null || !MessageDigest.isEqual(recipient.profileKey, profileKey)) {
val database = DatabaseFactory.getRecipientDatabase(context)
database.setProfileKey(recipient, profileKey)
database.setProfileAvatar(recipient, url)
ApplicationContext.getInstance(context).updatePublicChatProfileAvatarIfNeeded()
}
}
}
var userDevices = setOf<String>()
var uniqueDevices = setOf<String>()