Merge pull request #111 from loki-project/security

Untie Profile Picture from Auth Token
This commit is contained in:
gmbnt 2020-02-24 10:58:28 +07:00 committed by GitHub
commit ef2ceff0c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 3 deletions

View File

@ -75,6 +75,7 @@ import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.redesign.utilities.Broadcaster; import org.thoughtcrime.securesms.loki.redesign.utilities.Broadcaster;
import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
@ -94,6 +95,7 @@ import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils; import org.webrtc.voiceengine.WebRtcAudioUtils;
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider; import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol; import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol;
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
@ -104,8 +106,12 @@ import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.LokiRSSFeed; import org.whispersystems.signalservice.loki.api.LokiRSSFeed;
import java.io.File;
import java.io.FileInputStream;
import java.security.SecureRandom;
import java.security.Security; import java.security.Security;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -191,6 +197,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
} }
} }
} }
// Loki - Resubmit profile picture if needed
resubmitProfilePictureIfNeeded();
// Loki - Set up public chat manager // Loki - Set up public chat manager
lokiPublicChatManager = new LokiPublicChatManager(this); lokiPublicChatManager = new LokiPublicChatManager(this);
updatePublicChatProfilePictureIfNeeded(); updatePublicChatProfilePictureIfNeeded();
@ -589,6 +597,30 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
if (lokiMessengerUpdatesFeedPoller != null) lokiMessengerUpdatesFeedPoller.startIfNeeded(); if (lokiMessengerUpdatesFeedPoller != null) lokiMessengerUpdatesFeedPoller.startIfNeeded();
} }
private void resubmitProfilePictureIfNeeded() {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userHexEncodedPublicKey == null) return;
long now = new Date().getTime();
long lastProfilePictureUpload = TextSecurePreferences.getLastProfilePictureUpload(this);
if (now - lastProfilePictureUpload <= 14 * 24 * 60 * 60 * 1000) return;
AsyncTask.execute(() -> {
String encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this);
byte[] profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey);
try {
File profilePicture = AvatarHelper.getAvatarFile(this, Address.fromSerialized(userHexEncodedPublicKey));
StreamDetails stream = new StreamDetails(new FileInputStream(profilePicture), "image/jpeg", profilePicture.length());
LokiFileServerAPI.shared.uploadProfilePicture(LokiFileServerAPI.shared.getServer(), profileKey, stream, () -> {
TextSecurePreferences.setLastProfilePictureUpload(this, new Date().getTime());
TextSecurePreferences.setProfileAvatarId(this, new SecureRandom().nextInt());
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey);
return Unit.INSTANCE;
});
} catch (Exception exception) {
// Do nothing
}
});
}
public void updatePublicChatProfilePictureIfNeeded() { public void updatePublicChatProfilePictureIfNeeded() {
AsyncTask.execute(() -> { AsyncTask.execute(() -> {
LokiPublicChatAPI publicChatAPI = null; LokiPublicChatAPI publicChatAPI = null;

View File

@ -58,14 +58,15 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.crypto.ProfileCipher; import org.whispersystems.signalservice.api.crypto.ProfileCipher;
import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.loki.api.LokiDotNetAPI; import org.whispersystems.signalservice.loki.api.LokiDotNetAPI;
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI; import org.whispersystems.signalservice.loki.api.LokiFileServerAPI;
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -73,6 +74,7 @@ import java.util.regex.Pattern;
import javax.inject.Inject; import javax.inject.Inject;
import kotlin.Unit;
import network.loki.messenger.R; import network.loki.messenger.R;
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
@ -408,7 +410,10 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
if (avatar != null) { if (avatar != null) {
Log.d("Loki", "Start uploading profile photo"); Log.d("Loki", "Start uploading profile photo");
LokiFileServerAPI storageAPI = LokiFileServerAPI.shared; LokiFileServerAPI storageAPI = LokiFileServerAPI.shared;
LokiDotNetAPI.UploadResult result = storageAPI.uploadProfilePicture(storageAPI.getServer(), profileKey, avatar); LokiDotNetAPI.UploadResult result = storageAPI.uploadProfilePicture(storageAPI.getServer(), profileKey, avatar, () -> {
TextSecurePreferences.setLastProfilePictureUpload(CreateProfileActivity.this, new Date().getTime());
return Unit.INSTANCE;
});
Log.d("Loki", "Profile photo uploaded, the url is " + result.getUrl()); Log.d("Loki", "Profile photo uploaded, the url is " + result.getUrl());
TextSecurePreferences.setProfileAvatarUrl(context, result.getUrl()); TextSecurePreferences.setProfileAvatarUrl(context, result.getUrl());
} else { } else {

View File

@ -45,6 +45,7 @@ import org.whispersystems.signalservice.loki.api.LokiFileServerAPI
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.File import java.io.File
import java.security.SecureRandom import java.security.SecureRandom
import java.util.*
class SettingsActivity : PassphraseRequiredActionBarActivity() { class SettingsActivity : PassphraseRequiredActionBarActivity() {
private lateinit var glide: GlideRequests private lateinit var glide: GlideRequests
@ -163,7 +164,9 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
val deferred = deferred<Unit, Exception>() val deferred = deferred<Unit, Exception>()
AsyncTask.execute { AsyncTask.execute {
val stream = StreamDetails(ByteArrayInputStream(profilePicture), "image/jpeg", profilePicture.size.toLong()) val stream = StreamDetails(ByteArrayInputStream(profilePicture), "image/jpeg", profilePicture.size.toLong())
val (_, url) = storageAPI.uploadProfilePicture(storageAPI.server, profileKey, stream) val (_, url) = storageAPI.uploadProfilePicture(storageAPI.server, profileKey, stream) {
TextSecurePreferences.setLastProfilePictureUpload(this@SettingsActivity, Date().time)
}
TextSecurePreferences.setProfileAvatarUrl(this, url) TextSecurePreferences.setProfileAvatarUrl(this, url)
deferred.resolve(Unit) deferred.resolve(Unit)
} }

View File

@ -1258,6 +1258,14 @@ public class TextSecurePreferences {
public static void setHasSeenOpenGroupSuggestionSheet(Context context) { public static void setHasSeenOpenGroupSuggestionSheet(Context context) {
setBooleanPreference(context, "has_seen_open_group_suggestion_sheet", true); setBooleanPreference(context, "has_seen_open_group_suggestion_sheet", true);
} }
public static long getLastProfilePictureUpload(Context context) {
return getLongPreference(context, "last_profile_picture_upload", 0);
}
public static void setLastProfilePictureUpload(Context context, long newValue) {
setLongPreference(context, "last_profile_picture_upload", newValue);
}
// endregion // endregion
public static void clearAll(Context context) { public static void clearAll(Context context) {