WIP: clean up signal protocols

This commit is contained in:
Ryan ZHAO 2021-02-19 11:03:58 +11:00
parent 13c2995746
commit 958ec690f1
49 changed files with 568 additions and 882 deletions

View File

@ -76,7 +76,6 @@ import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
import org.thoughtcrime.securesms.loki.utilities.Broadcaster; import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities; import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities;
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier; import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
@ -84,7 +83,6 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier; import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
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.session.libsession.messaging.threads.recipients.Recipient;
import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.IncomingMessageObserver; import org.thoughtcrime.securesms.service.IncomingMessageObserver;
import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.service.KeyCachingService;
@ -107,8 +105,7 @@ import org.session.libsignal.service.loki.api.opengroups.PublicChatAPI;
import org.session.libsignal.service.loki.api.shelved.p2p.LokiP2PAPI; import org.session.libsignal.service.loki.api.shelved.p2p.LokiP2PAPI;
import org.session.libsignal.service.loki.api.shelved.p2p.LokiP2PAPIDelegate; import org.session.libsignal.service.loki.api.shelved.p2p.LokiP2PAPIDelegate;
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol; import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol;
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager; import org.session.libsignal.service.loki.utilities.mentions.MentionsManager;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -136,7 +133,6 @@ import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant;
public class ApplicationContext extends MultiDexApplication implements DependencyInjector, DefaultLifecycleObserver, LokiP2PAPIDelegate { public class ApplicationContext extends MultiDexApplication implements DependencyInjector, DefaultLifecycleObserver, LokiP2PAPIDelegate {
private static final String TAG = ApplicationContext.class.getSimpleName(); private static final String TAG = ApplicationContext.class.getSimpleName();
private final static int OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024; // 10 MB
private ExpiringMessageManager expiringMessageManager; private ExpiringMessageManager expiringMessageManager;
private TypingStatusRepository typingStatusRepository; private TypingStatusRepository typingStatusRepository;
@ -144,7 +140,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
private JobManager jobManager; private JobManager jobManager;
private ReadReceiptManager readReceiptManager; private ReadReceiptManager readReceiptManager;
private ProfileManager profileManager; private ProfileManager profileManager;
private IncomingMessageObserver incomingMessageObserver;
private ObjectGraph objectGraph; private ObjectGraph objectGraph;
private PersistentLogger persistentLogger; private PersistentLogger persistentLogger;
@ -182,7 +177,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this); LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this); LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
String userPublicKey = TextSecurePreferences.getLocalNumber(this); String userPublicKey = TextSecurePreferences.getLocalNumber(this);
SessionResetImplementation sessionResetImpl = new SessionResetImplementation(this);
MessagingConfiguration.Companion.configure(this, MessagingConfiguration.Companion.configure(this,
DatabaseFactory.getStorage(this), DatabaseFactory.getStorage(this),
DatabaseFactory.getAttachmentProvider(this), DatabaseFactory.getAttachmentProvider(this),
@ -191,7 +185,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
SwarmAPI.Companion.configureIfNeeded(apiDB); SwarmAPI.Companion.configureIfNeeded(apiDB);
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster); SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
MentionsManager.Companion.configureIfNeeded(userPublicKey, threadDB, userDB); MentionsManager.Companion.configureIfNeeded(userPublicKey, threadDB, userDB);
SessionMetaProtocol.Companion.configureIfNeeded(apiDB, userPublicKey);
} }
setUpP2PAPIIfNeeded(); setUpP2PAPIIfNeeded();
PushNotificationAPI.Companion.configureIfNeeded(BuildConfig.DEBUG); PushNotificationAPI.Companion.configureIfNeeded(BuildConfig.DEBUG);
@ -206,7 +199,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
UiModeUtilities.setupUiModeToUserSelected(this); UiModeUtilities.setupUiModeToUserSelected(this);
// ======== // ========
initializeJobManager(); initializeJobManager();
initializeMessageRetrieval();
initializeExpiringMessageManager(); initializeExpiringMessageManager();
initializeTypingStatusRepository(); initializeTypingStatusRepository();
initializeTypingStatusSender(); initializeTypingStatusSender();
@ -347,10 +339,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
.build()); .build());
} }
public void initializeMessageRetrieval() {
this.incomingMessageObserver = new IncomingMessageObserver(this);
}
private void initializeDependencyInjection() { private void initializeDependencyInjection() {
communicationModule = new SignalCommunicationModule(this, new SignalServiceNetworkAccess(this)); communicationModule = new SignalCommunicationModule(this, new SignalServiceNetworkAccess(this));
this.objectGraph = ObjectGraph.create(communicationModule); this.objectGraph = ObjectGraph.create(communicationModule);

View File

@ -90,9 +90,8 @@ import org.session.libsession.utilities.MediaTypes;
import org.session.libsignal.libsignal.InvalidMessageException; import org.session.libsignal.libsignal.InvalidMessageException;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.loki.api.opengroups.PublicChat; import org.session.libsignal.service.loki.api.opengroups.PublicChat;
import org.session.libsignal.service.loki.protocol.mentions.Mention; import org.session.libsignal.service.loki.utilities.mentions.Mention;
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager; import org.session.libsignal.service.loki.utilities.mentions.MentionsManager;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import org.session.libsignal.service.loki.utilities.HexEncodingKt; import org.session.libsignal.service.loki.utilities.HexEncodingKt;
import org.session.libsignal.service.loki.utilities.PublicKeyValidation; import org.session.libsignal.service.loki.utilities.PublicKeyValidation;
import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.ApplicationContext;
@ -144,7 +143,6 @@ import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2;
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt; import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities; import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities; import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities;
@ -404,7 +402,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}); });
sessionRestoreBannerView.setOnRestore(() -> { sessionRestoreBannerView.setOnRestore(() -> {
SessionManagementProtocol.startSessionReset(this, recipient.getAddress().serialize());
updateSessionRestoreBanner(); updateSessionRestoreBanner();
return Unit.INSTANCE; return Unit.INSTANCE;
}); });
@ -2003,7 +2000,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
Log.w(TAG, ex); Log.w(TAG, ex);
} }
if (messageStatus == null && !isGroupConversation() && !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize())) { if (messageStatus == null && !isGroupConversation() && !(TextSecurePreferences.getLocalNumber(this).equals(recipient.getAddress().serialize()))) {
messageStatus = "calculatingPoW"; messageStatus = "calculatingPoW";
updateSubtitleTextView(); updateSubtitleTextView();
updateMessageStatusProgressBar(); updateMessageStatusProgressBar();
@ -2680,7 +2677,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
private void handleMessageStatusChanged(String newMessageStatus, long timestamp) { private void handleMessageStatusChanged(String newMessageStatus, long timestamp) {
if (timestamp == 0 || SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()) ) { return; } if (timestamp == 0 || (TextSecurePreferences.getLocalNumber(this).equals(recipient.getAddress().serialize())) ) { return; }
updateForNewMessageStatusIfNeeded(newMessageStatus, timestamp); updateForNewMessageStatusIfNeeded(newMessageStatus, timestamp);
if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) { if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) {
new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000); new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000);

View File

@ -49,11 +49,11 @@ public class PushDatabase extends Database {
values.put(TYPE, envelope.getType()); values.put(TYPE, envelope.getType());
values.put(SOURCE, envelope.getSource()); values.put(SOURCE, envelope.getSource());
values.put(DEVICE_ID, envelope.getSourceDevice()); values.put(DEVICE_ID, envelope.getSourceDevice());
values.put(LEGACY_MSG, envelope.hasLegacyMessage() ? Base64.encodeBytes(envelope.getLegacyMessage()) : ""); values.put(LEGACY_MSG, "");
values.put(CONTENT, envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : ""); values.put(CONTENT, envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : "");
values.put(TIMESTAMP, envelope.getTimestamp()); values.put(TIMESTAMP, envelope.getTimestamp());
values.put(SERVER_TIMESTAMP, envelope.getServerTimestamp()); values.put(SERVER_TIMESTAMP, envelope.getServerTimestamp());
values.put(SERVER_GUID, envelope.getUuid()); values.put(SERVER_GUID, "");
return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values); return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
} }
@ -68,17 +68,14 @@ public class PushDatabase extends Database {
null, null, null); null, null, null);
if (cursor != null && cursor.moveToNext()) { if (cursor != null && cursor.moveToNext()) {
String legacyMessage = cursor.getString(cursor.getColumnIndexOrThrow(LEGACY_MSG));
String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT)); String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT));
return new SignalServiceEnvelope(cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)), return new SignalServiceEnvelope(cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)),
cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)), cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)),
cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)), cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)),
cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)), cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)),
Util.isEmpty(legacyMessage) ? null : Base64.decode(legacyMessage),
Util.isEmpty(content) ? null : Base64.decode(content), Util.isEmpty(content) ? null : Base64.decode(content),
cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_TIMESTAMP)), cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_TIMESTAMP)));
cursor.getString(cursor.getColumnIndexOrThrow(SERVER_GUID)));
} }
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, e); Log.w(TAG, e);
@ -114,7 +111,7 @@ public class PushDatabase extends Database {
new String[] {String.valueOf(envelope.getType()), new String[] {String.valueOf(envelope.getType()),
envelope.getSource(), envelope.getSource(),
String.valueOf(envelope.getSourceDevice()), String.valueOf(envelope.getSourceDevice()),
envelope.hasLegacyMessage() ? Base64.encodeBytes(envelope.getLegacyMessage()) : "", "",
envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : "", envelope.hasContent() ? Base64.encodeBytes(envelope.getContent()) : "",
String.valueOf(envelope.getTimestamp())}, String.valueOf(envelope.getTimestamp())},
null, null, null); null, null, null);
@ -144,16 +141,13 @@ public class PushDatabase extends Database {
int type = cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)); int type = cursor.getInt(cursor.getColumnIndexOrThrow(TYPE));
String source = cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)); String source = cursor.getString(cursor.getColumnIndexOrThrow(SOURCE));
int deviceId = cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)); int deviceId = cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID));
String legacyMessage = cursor.getString(cursor.getColumnIndexOrThrow(LEGACY_MSG));
String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT)); String content = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT));
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)); long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP));
long serverTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_TIMESTAMP)); long serverTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(SERVER_TIMESTAMP));
String serverGuid = cursor.getString(cursor.getColumnIndexOrThrow(SERVER_GUID));
return new SignalServiceEnvelope(type, source, deviceId, timestamp, return new SignalServiceEnvelope(type, source, deviceId, timestamp,
legacyMessage != null ? Base64.decode(legacyMessage) : null,
content != null ? Base64.decode(content) : null, content != null ? Base64.decode(content) : null,
serverTimestamp, serverGuid); serverTimestamp);
} catch (IOException e) { } catch (IOException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }

View File

@ -250,7 +250,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
} }
if (oldVersion < lokiV21) { if (oldVersion < lokiV21) {
deleteJobRecords(db, "ClosedGroupUpdateMessageSendJob"); deleteJobRecords(db,
"ClosedGroupUpdateMessageSendJob",
"NullMessageSendJob");
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();

View File

@ -32,7 +32,6 @@ import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository; import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
import org.session.libsignal.utilities.logging.Log; import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl; import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment; import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.push.MessageSenderEventListener; import org.thoughtcrime.securesms.push.MessageSenderEventListener;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
@ -88,20 +87,15 @@ public class SignalCommunicationModule {
@Provides @Provides
public synchronized SignalServiceMessageSender provideSignalMessageSender() { public synchronized SignalServiceMessageSender provideSignalMessageSender() {
if (this.messageSender == null) { if (this.messageSender == null) {
this.messageSender = new SignalServiceMessageSender(networkAccess.getConfiguration(context), this.messageSender = new SignalServiceMessageSender(new DynamicCredentialsProvider(context),
new DynamicCredentialsProvider(context),
new SignalProtocolStoreImpl(context), new SignalProtocolStoreImpl(context),
BuildConfig.USER_AGENT,
Optional.fromNullable(IncomingMessageObserver.getPipe()), Optional.fromNullable(IncomingMessageObserver.getPipe()),
Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()), Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()),
Optional.of(new MessageSenderEventListener(context)),
TextSecurePreferences.getLocalNumber(context), TextSecurePreferences.getLocalNumber(context),
DatabaseFactory.getLokiAPIDatabase(context), DatabaseFactory.getLokiAPIDatabase(context),
DatabaseFactory.getLokiThreadDatabase(context), DatabaseFactory.getLokiThreadDatabase(context),
DatabaseFactory.getLokiMessageDatabase(context), DatabaseFactory.getLokiMessageDatabase(context),
null, // DatabaseFactory.getLokiPreKeyBundleDatabase(context)
new SessionProtocolImpl(context), new SessionProtocolImpl(context),
new SessionResetImplementation(context),
DatabaseFactory.getLokiUserDatabase(context), DatabaseFactory.getLokiUserDatabase(context),
DatabaseFactory.getGroupDatabase(context), DatabaseFactory.getGroupDatabase(context),
((ApplicationContext)context.getApplicationContext()).broadcaster); ((ApplicationContext)context.getApplicationContext()).broadcaster);

View File

@ -17,7 +17,6 @@ import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintOb
import org.thoughtcrime.securesms.loki.api.PrepareAttachmentAudioExtrasJob; import org.thoughtcrime.securesms.loki.api.PrepareAttachmentAudioExtrasJob;
import org.thoughtcrime.securesms.loki.api.ResetThreadSessionJob; import org.thoughtcrime.securesms.loki.api.ResetThreadSessionJob;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupUpdateMessageSendJobV2; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupUpdateMessageSendJobV2;
import org.thoughtcrime.securesms.loki.protocol.NullMessageSendJob;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -41,7 +40,6 @@ public final class JobManagerFactories {
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory()); put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory()); put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory());
put(MmsSendJob.KEY, new MmsSendJob.Factory()); put(MmsSendJob.KEY, new MmsSendJob.Factory());
put(NullMessageSendJob.KEY, new NullMessageSendJob.Factory());
put(PushContentReceiveJob.KEY, new PushContentReceiveJob.Factory()); put(PushContentReceiveJob.KEY, new PushContentReceiveJob.Factory());
put(PushDecryptJob.KEY, new PushDecryptJob.Factory()); put(PushDecryptJob.KEY, new PushDecryptJob.Factory());
put(PushGroupSendJob.KEY, new PushGroupSendJob.Factory()); put(PushGroupSendJob.KEY, new PushGroupSendJob.Factory());

View File

@ -17,19 +17,8 @@ import com.annimon.stream.Stream;
import org.session.libsession.messaging.jobs.Data; import org.session.libsession.messaging.jobs.Data;
import org.session.libsession.utilities.MediaTypes; import org.session.libsession.utilities.MediaTypes;
import org.session.libsignal.metadata.InvalidMetadataMessageException; import org.session.libsignal.metadata.InvalidMetadataMessageException;
import org.session.libsignal.metadata.InvalidMetadataVersionException;
import org.session.libsignal.metadata.ProtocolDuplicateMessageException;
import org.session.libsignal.metadata.ProtocolInvalidKeyException;
import org.session.libsignal.metadata.ProtocolInvalidKeyIdException;
import org.session.libsignal.metadata.ProtocolInvalidMessageException; import org.session.libsignal.metadata.ProtocolInvalidMessageException;
import org.session.libsignal.metadata.ProtocolInvalidVersionException;
import org.session.libsignal.metadata.ProtocolLegacyMessageException;
import org.session.libsignal.metadata.ProtocolNoSessionException;
import org.session.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.session.libsignal.metadata.SelfSendException;
import org.session.libsignal.service.api.crypto.SignalServiceCipher; import org.session.libsignal.service.api.crypto.SignalServiceCipher;
import org.session.libsignal.service.loki.api.crypto.SessionProtocol;
import org.session.libsignal.utilities.PromiseUtilities;
import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.ApplicationContext;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview; import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
@ -48,13 +37,10 @@ import org.session.libsession.utilities.TextSecurePreferences;
import org.thoughtcrime.securesms.contactshare.ContactModelMapper; import org.thoughtcrime.securesms.contactshare.ContactModelMapper;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl; import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase;
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult; import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase;
@ -79,26 +65,19 @@ import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocolV2;
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities; import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage; import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.mms.StickerSlide; import org.thoughtcrime.securesms.mms.StickerSlide;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage; import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage; import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.session.libsignal.utilities.Hex; import org.session.libsignal.utilities.Hex;
import org.session.libsignal.libsignal.InvalidMessageException; import org.session.libsignal.libsignal.InvalidMessageException;
import org.session.libsignal.libsignal.loki.SessionResetProtocol;
import org.session.libsignal.libsignal.state.SignalProtocolStore; import org.session.libsignal.libsignal.state.SignalProtocolStore;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.SignalServiceMessageSender; import org.session.libsignal.service.api.SignalServiceMessageSender;
@ -111,16 +90,14 @@ import org.session.libsignal.service.api.messages.SignalServiceReceiptMessage;
import org.session.libsignal.service.api.messages.SignalServiceTypingMessage; import org.session.libsignal.service.api.messages.SignalServiceTypingMessage;
import org.session.libsignal.service.api.messages.shared.SharedContact; import org.session.libsignal.service.api.messages.shared.SharedContact;
import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsignal.service.api.push.SignalServiceAddress;
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager; import org.session.libsignal.service.loki.utilities.mentions.MentionsManager;
import org.session.libsignal.service.loki.utilities.PublicKeyValidation; import org.session.libsignal.service.loki.utilities.PublicKeyValidation;
import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
@ -242,10 +219,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
try { try {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context); SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context);
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context)); SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(context); LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(context);
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, sessionResetProtocol, new SessionProtocolImpl(context), apiDB); SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore, new SessionProtocolImpl(context), apiDB);
SignalServiceContent content = cipher.decrypt(envelope); SignalServiceContent content = cipher.decrypt(envelope);
@ -254,8 +230,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return; return;
} }
SessionManagementProtocol.handlePreKeyBundleMessageIfNeeded(context, content);
SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content); SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content);
if (content.configurationMessageProto.isPresent()) { if (content.configurationMessageProto.isPresent()) {
@ -341,7 +315,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} }
if (threadId != null) { if (threadId != null) {
SessionManagementProtocol.handleEndSessionMessageIfNeeded(context, content);
messageNotifier.updateNotification(context, threadId); messageNotifier.updateNotification(context, threadId);
} }
} }
@ -706,82 +679,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
smsDatabase.markAsDecryptFailed(smsMessageId.get()); smsDatabase.markAsDecryptFailed(smsMessageId.get());
} }
} }
if (canRecoverAutomatically(e)) {
Recipient recipient = Recipient.from(context, Address.fromSerialized(sender), false);
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(context);
long threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
threadDB.addSessionRestoreDevice(threadID, sender);
SessionManagementProtocol.startSessionReset(context, sender);
} else {
SessionManagementProtocol.triggerSessionRestorationUI(context, sender, timestamp);
}
}
private boolean canRecoverAutomatically(Throwable e) {
// Corrupt message exception
if (e.getCause() != null) {
Throwable e2 = e.getCause();
if (e2.getCause() != null) {
Throwable e3 = e2.getCause();
if (e3 instanceof InvalidMessageException) {
String message = e3.getMessage();
return (message != null && message.startsWith("Bad Mac!"));
}
}
}
return false;
}
private void handleNoSessionMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional<Long> smsMessageId)
{
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!SessionMetaProtocol.shouldIgnoreDecryptionException(context, timestamp)) {
if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
if (insertResult.isPresent()) {
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
} else {
smsDatabase.markAsNoSession(smsMessageId.get());
}
}
}
private void handleLegacyMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional<Long> smsMessageId)
{
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
if (insertResult.isPresent()) {
smsDatabase.markAsLegacyVersion(insertResult.get().getMessageId());
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
}
} else {
smsDatabase.markAsLegacyVersion(smsMessageId.get());
}
}
@SuppressWarnings("unused")
private void handleDuplicateMessage(@NonNull String sender, int senderDeviceId, long timestamp,
@NonNull Optional<Long> smsMessageId)
{
// Let's start ignoring these now
// SmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
//
// if (smsMessageId <= 0) {
// Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, envelope);
// smsDatabase.markAsDecryptDuplicate(messageAndThreadId.first);
// MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
// } else {
// smsDatabase.markAsDecryptDuplicate(smsMessageId);
// }
} }
private void handleNeedsDeliveryReceipt(@NonNull SignalServiceContent content, private void handleNeedsDeliveryReceipt(@NonNull SignalServiceContent content,
@ -905,42 +802,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
PointerAttachment.forPointersOfDataMessage(quote.get().getAttachments()))); PointerAttachment.forPointersOfDataMessage(quote.get().getAttachments())));
} }
private Optional<Attachment> getStickerAttachment(Optional<SignalServiceDataMessage.Sticker> sticker) {
if (!sticker.isPresent()) {
return Optional.absent();
}
if (sticker.get().getPackId() == null || sticker.get().getPackKey() == null || sticker.get().getAttachment() == null) {
Log.w(TAG, "Malformed sticker!");
return Optional.absent();
}
String packId = Hex.toStringCondensed(sticker.get().getPackId());
String packKey = Hex.toStringCondensed(sticker.get().getPackKey());
int stickerId = sticker.get().getStickerId();
StickerLocator stickerLocator = new StickerLocator(packId, packKey, stickerId);
StickerDatabase stickerDatabase = DatabaseFactory.getStickerDatabase(context);
StickerRecord stickerRecord = stickerDatabase.getSticker(stickerLocator.getPackId(), stickerLocator.getStickerId(), false);
if (stickerRecord != null) {
return Optional.of(new UriAttachment(stickerRecord.getUri(),
stickerRecord.getUri(),
MediaTypes.IMAGE_WEBP,
AttachmentDatabase.TRANSFER_PROGRESS_DONE,
stickerRecord.getSize(),
StickerSlide.WIDTH,
StickerSlide.HEIGHT,
null,
String.valueOf(new SecureRandom().nextLong()),
false,
false,
null,
stickerLocator));
} else {
return Optional.of(PointerAttachment.forPointer(Optional.of(sticker.get().getAttachment()), stickerLocator).get());
}
}
private Optional<List<Contact>> getContacts(Optional<List<SharedContact>> sharedContacts) { private Optional<List<Contact>> getContacts(Optional<List<SharedContact>> sharedContacts) {
if (!sharedContacts.isPresent()) return Optional.absent(); if (!sharedContacts.isPresent()) return Optional.absent();
@ -1069,10 +930,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return false; return false;
} }
private boolean isGroupChatMessage(SignalServiceContent content) {
return content.getDataMessage().isPresent() && content.getDataMessage().get().isGroupMessage();
}
private void resetRecipientToPush(@NonNull Recipient recipient) { private void resetRecipientToPush(@NonNull Recipient recipient) {
if (recipient.isForceSmsSelection()) { if (recipient.isForceSmsSelection()) {
DatabaseFactory.getRecipientDatabase(context).setForceSmsSelection(recipient, false); DatabaseFactory.getRecipientDatabase(context).setForceSmsSelection(recipient, false);

View File

@ -39,12 +39,10 @@ import org.session.libsignal.service.api.messages.SendMessageResult;
import org.session.libsignal.service.api.messages.SignalServiceAttachment; import org.session.libsignal.service.api.messages.SignalServiceAttachment;
import org.session.libsignal.service.api.messages.SignalServiceDataMessage; import org.session.libsignal.service.api.messages.SignalServiceDataMessage;
import org.session.libsignal.service.api.messages.SignalServiceDataMessage.Preview; import org.session.libsignal.service.api.messages.SignalServiceDataMessage.Preview;
import org.session.libsignal.service.api.messages.multidevice.SignalServiceSyncMessage;
import org.session.libsignal.service.api.messages.shared.SharedContact; import org.session.libsignal.service.api.messages.shared.SharedContact;
import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsignal.service.api.push.SignalServiceAddress;
import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException; import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException;
import org.session.libsignal.service.loki.api.SnodeAPI; import org.session.libsignal.service.loki.api.SnodeAPI;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -285,7 +283,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
.asExpirationUpdate(message.isExpirationUpdate()) .asExpirationUpdate(message.isExpirationUpdate())
.build(); .build();
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) { if (userPublicKey == address.getNumber()) {
// Loki - Device link messages don't go through here // Loki - Device link messages don't go through here
SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccessPair, mediaMessage); SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccessPair, mediaMessage);
if (result.getLokiAPIError() != null) { if (result.getLokiAPIError() != null) {

View File

@ -33,10 +33,7 @@ public abstract class PushReceivedJob extends BaseJob {
} }
} }
if (envelope.isReceipt()) { if (envelope.isUnidentifiedSender() || envelope.isClosedGroupCiphertext()) {
handleReceipt(envelope);
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()
|| envelope.isUnidentifiedSender() || envelope.isFallbackMessage() || envelope.isClosedGroupCiphertext()) {
handleMessage(envelope, isPushNotification); handleMessage(envelope, isPushNotification);
} else { } else {
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType()); Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
@ -51,13 +48,6 @@ public abstract class PushReceivedJob extends BaseJob {
new PushDecryptJob(context).processMessage(envelope, isPushNotification); new PushDecryptJob(context).processMessage(envelope, isPushNotification);
} }
@SuppressLint("DefaultLocale")
private void handleReceipt(SignalServiceEnvelope envelope) {
Log.i(TAG, String.format("Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()),
envelope.getTimestamp()), System.currentTimeMillis());
}
private boolean isActiveNumber(@NonNull Recipient recipient) { private boolean isActiveNumber(@NonNull Recipient recipient) {
return recipient.resolve().getRegistered() == Recipient.RegisteredState.REGISTERED; return recipient.resolve().getRegistered() == Recipient.RegisteredState.REGISTERED;
} }

View File

@ -12,7 +12,6 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact; import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.utilities.MediaTypes; import org.session.libsession.utilities.MediaTypes;
import org.session.libsignal.utilities.Base64; import org.session.libsignal.utilities.Base64;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util; import org.session.libsession.utilities.Util;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@ -34,13 +33,10 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
import org.session.libsignal.utilities.Hex; import org.session.libsignal.utilities.Hex;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair;
import org.session.libsignal.service.api.messages.SignalServiceAttachment; import org.session.libsignal.service.api.messages.SignalServiceAttachment;
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer; import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer;
import org.session.libsignal.service.api.messages.SignalServiceDataMessage; import org.session.libsignal.service.api.messages.SignalServiceDataMessage;
import org.session.libsignal.service.api.messages.SignalServiceDataMessage.Preview; import org.session.libsignal.service.api.messages.SignalServiceDataMessage.Preview;
import org.session.libsignal.service.api.messages.multidevice.SentTranscriptMessage;
import org.session.libsignal.service.api.messages.multidevice.SignalServiceSyncMessage;
import org.session.libsignal.service.api.messages.shared.SharedContact; import org.session.libsignal.service.api.messages.shared.SharedContact;
import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsignal.service.api.push.SignalServiceAddress;
@ -55,7 +51,6 @@ import java.util.concurrent.TimeUnit;
public abstract class PushSendJob extends SendJob { public abstract class PushSendJob extends SendJob {
private static final String TAG = PushSendJob.class.getSimpleName(); private static final String TAG = PushSendJob.class.getSimpleName();
private static final long CERTIFICATE_EXPIRATION_BUFFER = TimeUnit.DAYS.toMillis(1);
protected PushSendJob(Job.Parameters parameters) { protected PushSendJob(Job.Parameters parameters) {
super(parameters); super(parameters);
@ -72,14 +67,6 @@ public abstract class PushSendJob extends SendJob {
@Override @Override
protected final void onSend() throws Exception { protected final void onSend() throws Exception {
// if (TextSecurePreferences.getSignedPreKeyFailureCount(context) > 5) {
// ApplicationContext.getInstance(context)
// .getJobManager()
// .add(new RotateSignedPreKeyJob());
//
// throw new TextSecureExpiredException("Too many signed prekey rotation failures");
// }
onPushSend(); onPushSend();
} }

View File

@ -30,11 +30,9 @@ import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair;
import org.session.libsignal.service.api.crypto.UntrustedIdentityException; import org.session.libsignal.service.api.crypto.UntrustedIdentityException;
import org.session.libsignal.service.api.messages.SendMessageResult; import org.session.libsignal.service.api.messages.SendMessageResult;
import org.session.libsignal.service.api.messages.SignalServiceDataMessage; import org.session.libsignal.service.api.messages.SignalServiceDataMessage;
import org.session.libsignal.service.api.messages.multidevice.SignalServiceSyncMessage;
import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsignal.service.api.push.SignalServiceAddress;
import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException; import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException;
import org.session.libsignal.service.loki.api.SnodeAPI; import org.session.libsignal.service.loki.api.SnodeAPI;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import java.io.IOException; import java.io.IOException;
@ -224,7 +222,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
.asEndSessionMessage(message.isEndSession()) .asEndSessionMessage(message.isEndSession())
.build(); .build();
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) { if (userPublicKey.equals(address.getNumber())) {
// Loki - Device link messages don't go through here // Loki - Device link messages don't go through here
SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccess, textSecureMessage); SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccess, textSecureMessage);
if (result.getLokiAPIError() != null) { if (result.getLokiAPIError() != null) {

View File

@ -87,16 +87,14 @@ public class TypingSendJob extends BaseJob implements InjectableType {
} }
List<Recipient> recipients = Collections.singletonList(recipient); List<Recipient> recipients = Collections.singletonList(recipient);
Optional<byte[]> groupId = Optional.absent();
if (recipient.isGroupRecipient()) { if (recipient.isGroupRecipient()) {
recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), false); recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), false);
groupId = Optional.of(GroupUtil.getDecodedGroupIDAsData(recipient.getAddress().toGroupString()));
} }
List<SignalServiceAddress> addresses = Stream.of(recipients).map(r -> new SignalServiceAddress(r.getAddress().serialize())).toList(); List<SignalServiceAddress> addresses = Stream.of(recipients).map(r -> new SignalServiceAddress(r.getAddress().serialize())).toList();
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(recipients).map(r -> UnidentifiedAccessUtil.getAccessFor(context, r)).toList(); List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(recipients).map(r -> UnidentifiedAccessUtil.getAccessFor(context, r)).toList();
SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis(), groupId); SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis());
messageSender.sendTyping(addresses, unidentifiedAccess, typingMessage); messageSender.sendTyping(addresses, unidentifiedAccess, typingMessage);
} }

View File

@ -193,8 +193,6 @@ class BackupRestoreViewModel(application: Application): AndroidViewModel(applica
application.setUpStorageAPIIfNeeded() application.setUpStorageAPIIfNeeded()
application.setUpP2PAPIIfNeeded() application.setUpP2PAPIIfNeeded()
HomeActivity.requestResetAllSessionsOnStartup(context)
BackupRestoreResult.SUCCESS BackupRestoreResult.SUCCESS
} catch (e: DatabaseDowngradeException) { } catch (e: DatabaseDowngradeException) {
Log.w(TAG, "Failed due to the backup being from a newer version of Signal.", e) Log.w(TAG, "Failed due to the backup being from a newer version of Signal.", e)

View File

@ -33,7 +33,6 @@ import org.session.libsession.utilities.GroupUtil
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.loki.api.ResetThreadSessionJob import org.thoughtcrime.securesms.loki.api.ResetThreadSessionJob
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation
import org.thoughtcrime.securesms.loki.utilities.* import org.thoughtcrime.securesms.loki.utilities.*
import org.thoughtcrime.securesms.loki.views.ConversationView import org.thoughtcrime.securesms.loki.views.ConversationView
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate
@ -44,8 +43,7 @@ import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.TextSecurePreferences.getBooleanPreference import org.session.libsession.utilities.TextSecurePreferences.getBooleanPreference
import org.session.libsession.utilities.TextSecurePreferences.setBooleanPreference import org.session.libsession.utilities.TextSecurePreferences.setBooleanPreference
import org.session.libsession.utilities.Util import org.session.libsession.utilities.Util
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol
import org.session.libsignal.utilities.ThreadUtils import org.session.libsignal.utilities.ThreadUtils
import org.session.libsignal.service.loki.utilities.toHexString import org.session.libsignal.service.loki.utilities.toHexString
import org.thoughtcrime.securesms.loki.dialogs.* import org.thoughtcrime.securesms.loki.dialogs.*
@ -54,31 +52,6 @@ import java.io.IOException
class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate { class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate {
companion object {
private const val PREF_RESET_ALL_SESSIONS_ON_START_UP = "pref_reset_all_sessions_on_start_up"
@JvmStatic
fun requestResetAllSessionsOnStartup(context: Context) {
setBooleanPreference(context, PREF_RESET_ALL_SESSIONS_ON_START_UP, true)
}
@JvmStatic
fun scheduleResetAllSessionsIfRequested(context: Context) {
if (!getBooleanPreference(context, PREF_RESET_ALL_SESSIONS_ON_START_UP, false)) return
setBooleanPreference(context, PREF_RESET_ALL_SESSIONS_ON_START_UP, false)
val jobManager = ApplicationContext.getInstance(context).jobManager
DatabaseFactory.getThreadDatabase(context).conversationListQuick.forEach { tuple ->
val threadId: Long = tuple.first
val recipientAddress: String = tuple.second
jobManager.add(ResetThreadSessionJob(
Address.fromSerialized(recipientAddress),
threadId))
}
}
}
private lateinit var glide: GlideRequests private lateinit var glide: GlideRequests
private var broadcastReceiver: BroadcastReceiver? = null private var broadcastReceiver: BroadcastReceiver? = null
@ -165,10 +138,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
val threadDB = DatabaseFactory.getLokiThreadDatabase(this) val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
val userDB = DatabaseFactory.getLokiUserDatabase(this) val userDB = DatabaseFactory.getLokiUserDatabase(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this) val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val sessionResetImpl = SessionResetImplementation(this)
if (userPublicKey != null) { if (userPublicKey != null) {
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB) MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
application.publicChatManager.startPollersIfNeeded() application.publicChatManager.startPollersIfNeeded()
} }
IP2Country.configureIfNeeded(this) IP2Country.configureIfNeeded(this)

View File

@ -153,67 +153,11 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
signalLinkPreviews.add(SignalServiceDataMessage.Preview(linkPreview.linkPreviewURL!!, linkPreview.linkPreviewTitle!!, Optional.of(attachment))) signalLinkPreviews.add(SignalServiceDataMessage.Preview(linkPreview.linkPreviewURL!!, linkPreview.linkPreviewTitle!!, Optional.of(attachment)))
} }
val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body val body = if (message.body == message.timestamp.toString()) "" else message.body // Workaround for the fact that the back-end doesn't accept messages without a body
return SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, 0, false, null, quote, null, signalLinkPreviews) val syncTarget = if (message.senderPublicKey == userHexEncodedPublicKey) group.id else null
return SignalServiceDataMessage(message.timestamp, serviceGroup, attachments, body, 0, false, null, quote, null, signalLinkPreviews, null, syncTarget)
} }
fun pollForNewMessages(): Promise<Unit, Exception> { fun pollForNewMessages(): Promise<Unit, Exception> {
fun processIncomingMessage(message: PublicChatMessage) {
// If the sender of the current message is not a slave device, set the display name in the database
val senderDisplayName = "${message.displayName} (...${message.senderPublicKey.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.senderPublicKey, senderDisplayName)
val senderHexEncodedPublicKey = message.senderPublicKey
val serviceDataMessage = getDataMessage(message)
val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.serverTimestamp, false)
if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) {
PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
} else {
PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
}
// Update profile picture if needed
val senderAsRecipient = Recipient.from(context, Address.fromSerialized(senderHexEncodedPublicKey), false)
if (message.profilePicture != null && message.profilePicture!!.url.isNotEmpty()) {
val profileKey = message.profilePicture!!.profileKey
val url = message.profilePicture!!.url
if (senderAsRecipient.profileKey == null || !MessageDigest.isEqual(senderAsRecipient.profileKey, profileKey)) {
val database = DatabaseFactory.getRecipientDatabase(context)
database.setProfileKey(senderAsRecipient, profileKey)
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, url))
}
}
}
fun processOutgoingMessage(message: PublicChatMessage) {
val messageServerID = message.serverID ?: return
val messageID = DatabaseFactory.getLokiMessageDatabase(context).getMessageID(messageServerID)
var isDuplicate = false
if (messageID != null) {
isDuplicate = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageID) >= 0
|| DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID) >= 0
}
if (isDuplicate) { return }
if (message.body.isEmpty() && message.attachments.isEmpty() && message.quote == null) { return }
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
val dataMessage = getDataMessage(message)
SessionMetaProtocol.dropFromTimestampCacheIfNeeded(message.serverTimestamp)
val transcript = SentTranscriptMessage(userHexEncodedPublicKey, message.serverTimestamp, dataMessage, dataMessage.expiresInSeconds.toLong(), Collections.singletonMap(userHexEncodedPublicKey, false))
transcript.messageServerID = messageServerID
if (dataMessage.quote.isPresent || (dataMessage.attachments.isPresent && dataMessage.attachments.get().size > 0) || dataMessage.previews.isPresent) {
PushDecryptJob(context).handleSynchronizeSentMediaMessage(transcript)
} else {
PushDecryptJob(context).handleSynchronizeSentTextMessage(transcript)
}
// If we got a message from our master device then make sure our mapping stays in sync
val recipient = Recipient.from(context, Address.fromSerialized(message.senderPublicKey), false)
if (message.profilePicture != null) {
val profileKey = message.profilePicture!!.profileKey
val url = message.profilePicture!!.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).updateOpenGroupProfilePicturesIfNeeded()
}
}
}
if (isPollOngoing) { return Promise.of(Unit) } if (isPollOngoing) { return Promise.of(Unit) }
isPollOngoing = true isPollOngoing = true
val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize()
@ -226,10 +170,27 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
promise.successBackground { messages -> promise.successBackground { messages ->
// Process messages in the background // Process messages in the background
messages.forEach { message -> messages.forEach { message ->
if (message.senderPublicKey == userHexEncodedPublicKey) { // If the sender of the current message is not a slave device, set the display name in the database
processOutgoingMessage(message) val senderDisplayName = "${message.displayName} (...${message.senderPublicKey.takeLast(8)})"
DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.senderPublicKey, senderDisplayName)
val senderHexEncodedPublicKey = message.senderPublicKey
val serviceDataMessage = getDataMessage(message)
val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.serverTimestamp, false)
if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) {
PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
} else { } else {
processIncomingMessage(message) PushDecryptJob(context).handleTextMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
}
// Update profile picture if needed
val senderAsRecipient = Recipient.from(context, Address.fromSerialized(senderHexEncodedPublicKey), false)
if (message.profilePicture != null && message.profilePicture!!.url.isNotEmpty()) {
val profileKey = message.profilePicture!!.profileKey
val url = message.profilePicture!!.url
if (senderAsRecipient.profileKey == null || !MessageDigest.isEqual(senderAsRecipient.profileKey, profileKey)) {
val database = DatabaseFactory.getRecipientDatabase(context)
database.setProfileKey(senderAsRecipient, profileKey)
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, url))
}
} }
} }
isCaughtUp = true isCaughtUp = true

View File

@ -14,7 +14,6 @@ import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.api.opengroups.PublicChat import org.session.libsignal.service.loki.api.opengroups.PublicChat
import org.session.libsignal.libsignal.loki.SessionResetStatus
import org.session.libsignal.utilities.JsonUtil import org.session.libsignal.utilities.JsonUtil
import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol
import org.session.libsignal.service.loki.utilities.PublicKeyValidation import org.session.libsignal.service.loki.utilities.PublicKeyValidation
@ -39,34 +38,6 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient) return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
} }
fun getThreadID(messageID: Long): Long {
return DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID)
}
fun getSessionResetStatus(hexEncodedPublicKey: String): SessionResetStatus {
val threadID = getThreadID(hexEncodedPublicKey)
val database = databaseHelper.readableDatabase
val result = database.get(sessionResetTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor ->
cursor.getInt(sessionResetStatus)
}
return if (result != null) {
SessionResetStatus.values().first { it.rawValue == result }
} else {
SessionResetStatus.NONE
}
}
fun setSessionResetStatus(hexEncodedPublicKey: String, sessionResetStatus: SessionResetStatus) {
val threadID = getThreadID(hexEncodedPublicKey)
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(2)
contentValues.put(Companion.threadID, threadID)
contentValues.put(Companion.sessionResetStatus, sessionResetStatus.rawValue)
database.insertOrUpdate(sessionResetTable, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
notifyConversationListListeners()
notifyConversationListeners(threadID)
}
fun getAllPublicChats(): Map<Long, PublicChat> { fun getAllPublicChats(): Map<Long, PublicChat> {
val database = databaseHelper.readableDatabase val database = databaseHelper.readableDatabase
var cursor: Cursor? = null var cursor: Cursor? = null

View File

@ -13,7 +13,7 @@ import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.push.SignalServiceAddress import org.session.libsignal.service.api.push.SignalServiceAddress
import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities import org.session.libsignal.service.loki.utilities.TTLUtilities
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
import org.session.libsignal.service.loki.utilities.toHexString import org.session.libsignal.service.loki.utilities.toHexString
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
@ -25,7 +25,6 @@ import org.session.libsignal.utilities.logging.Log
import org.thoughtcrime.securesms.loki.utilities.recipient import org.thoughtcrime.securesms.loki.utilities.recipient
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Parameters, private val destination: String, private val kind: Kind, private val sentTime: Long) : BaseJob(parameters) { class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Parameters, private val destination: String, private val kind: Kind, private val sentTime: Long) : BaseJob(parameters) {

View File

@ -8,6 +8,7 @@ import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.libsignal.util.guava.Optional import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.push.SignalServiceAddress import org.session.libsignal.service.api.push.SignalServiceAddress
import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.logging.Log import org.session.libsignal.utilities.logging.Log
@ -72,8 +73,8 @@ object MultiDeviceProtocol {
for (closedGroup in configurationMessage.closedGroups) { for (closedGroup in configurationMessage.closedGroups) {
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue
val closedGroupUpdate = SignalServiceProtos.ClosedGroupUpdateV2.newBuilder() val closedGroupUpdate = DataMessage.ClosedGroupControlMessage.newBuilder()
closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW closedGroupUpdate.type = DataMessage.ClosedGroupControlMessage.Type.NEW
closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey)) closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey))
closedGroupUpdate.name = closedGroup.name closedGroupUpdate.name = closedGroup.name
val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder() val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder()

View File

@ -1,85 +0,0 @@
package org.thoughtcrime.securesms.loki.protocol
import com.google.protobuf.ByteString
import org.session.libsession.messaging.jobs.Data
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil
import org.session.libsession.messaging.threads.Address
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.jobs.BaseJob
import org.session.libsignal.utilities.logging.Log
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.push.SignalServiceAddress
import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities
import java.io.IOException
import java.security.SecureRandom
import java.util.*
import java.util.concurrent.TimeUnit
class NullMessageSendJob private constructor(parameters: Parameters, private val publicKey: String) : BaseJob(parameters) {
companion object {
const val KEY = "NullMessageSendJob"
}
constructor(publicKey: String) : this(Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setQueue(KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(1)
.build(),
publicKey)
override fun serialize(): Data {
return Data.Builder().putString("publicKey", publicKey).build()
}
override fun getFactoryKey(): String { return KEY }
public override fun onRun() {
val contentMessage = SignalServiceProtos.Content.newBuilder()
val nullMessage = SignalServiceProtos.NullMessage.newBuilder()
val sr = SecureRandom()
val paddingSize = sr.nextInt(512)
val padding = ByteArray(paddingSize)
sr.nextBytes(padding)
nullMessage.padding = ByteString.copyFrom(padding)
contentMessage.nullMessage = nullMessage.build()
val serializedContentMessage = contentMessage.build().toByteArray()
val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender()
val address = SignalServiceAddress(publicKey)
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
val udAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient)
val ttl = TTLUtilities.getTTL(TTLUtilities.MessageType.Ephemeral)
try {
messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess,
Date().time, serializedContentMessage, false, ttl,
false, false, false, Optional.absent())
} catch (e: Exception) {
Log.d("Loki", "Failed to send null message to: $publicKey due to error: $e.")
throw e
}
}
public override fun onShouldRetry(e: Exception): Boolean {
// Disable since we have our own retrying
return false
}
override fun onCanceled() { }
class Factory : Job.Factory<NullMessageSendJob> {
override fun create(parameters: Parameters, data: Data): NullMessageSendJob {
try {
val publicKey = data.getString("publicKey")
return NullMessageSendJob(parameters, publicKey)
} catch (e: IOException) {
throw AssertionError(e)
}
}
}
}

View File

@ -1,102 +0,0 @@
package org.thoughtcrime.securesms.loki.protocol
import android.content.Context
import org.session.libsignal.utilities.logging.Log
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.SecurityEvent
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.utilities.recipient
import org.thoughtcrime.securesms.sms.MessageSender
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.libsignal.loki.SessionResetStatus
import org.session.libsignal.service.api.messages.SignalServiceContent
import java.util.*
object SessionManagementProtocol {
@JvmStatic
fun startSessionReset(context: Context, publicKey: String) {
val recipient = recipient(context, publicKey)
if (recipient.isGroupRecipient) { return }
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
val devices = lokiThreadDB.getSessionRestoreDevices(threadID)
for (device in devices) {
val endSessionMessage = OutgoingEndSessionMessage(OutgoingTextMessage(recipient, "TERMINATE", 0, -1))
MessageSender.send(context, endSessionMessage, threadID, false, null)
}
val smsDB = DatabaseFactory.getSmsDatabase(context)
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
if (infoMessageID > -1) {
smsDB.markAsSentLokiSessionRestorationRequest(infoMessageID)
}
lokiThreadDB.removeAllSessionRestoreDevices(threadID)
}
// @JvmStatic
// fun refreshSignedPreKey(context: Context) {
// if (TextSecurePreferences.isSignedPreKeyRegistered(context)) {
// Log.d("Loki", "Skipping signed pre key refresh; using existing signed pre key.")
// } else {
// Log.d("Loki", "Signed pre key refreshed successfully.")
// val identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context)
// PreKeyUtil.generateSignedPreKey(context, identityKeyPair, true)
// TextSecurePreferences.setSignedPreKeyRegistered(context, true)
// ApplicationContext.getInstance(context).jobManager.add(CleanPreKeysJob())
// }
// }
@JvmStatic
fun shouldProcessSessionRequest(context: Context, publicKey: String, timestamp: Long): Boolean {
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
val sentTimestamp = apiDB.getSessionRequestSentTimestamp(publicKey) ?: 0
val processedTimestamp = apiDB.getSessionRequestProcessedTimestamp(publicKey) ?: 0
val restorationTimestamp = TextSecurePreferences.getRestorationTime(context)
return timestamp > sentTimestamp && timestamp > processedTimestamp && timestamp > restorationTimestamp
}
@JvmStatic
fun handlePreKeyBundleMessageIfNeeded(context: Context, content: SignalServiceContent) {
val preKeyBundleMessage = content.preKeyBundleMessage.orNull() ?: return
val publicKey = content.sender
if (recipient(context, publicKey).isGroupRecipient) { return } // Should never occur
Log.d("Loki", "Received a pre key bundle from: $publicKey.")
if (!shouldProcessSessionRequest(context, publicKey, content.timestamp)) {
Log.d("Loki", "Ignoring session request from: $publicKey.")
return
}
val registrationID = TextSecurePreferences.getLocalRegistrationId(context)
// val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context)
val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID)
// lokiPreKeyBundleDatabase.setPreKeyBundle(publicKey, preKeyBundle)
DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestProcessedTimestamp(publicKey, Date().time)
val job = NullMessageSendJob(publicKey)
ApplicationContext.getInstance(context).jobManager.add(job)
}
@JvmStatic
fun handleEndSessionMessageIfNeeded(context: Context, content: SignalServiceContent) {
if (!content.dataMessage.isPresent || !content.dataMessage.get().isEndSession) { return }
val sessionStore = TextSecureSessionStore(context)
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
Log.d("Loki", "Received a session reset request from: ${content.sender}; archiving the session.")
sessionStore.archiveAllSessions(content.sender)
lokiThreadDB.setSessionResetStatus(content.sender, SessionResetStatus.REQUEST_RECEIVED)
Log.d("Loki", "Sending an ephemeral message back to: ${content.sender}.")
val job = NullMessageSendJob(content.sender)
ApplicationContext.getInstance(context).jobManager.add(job)
SecurityEvent.broadcastSecurityUpdateEvent(context)
}
@JvmStatic
fun triggerSessionRestorationUI(context: Context, publicKey: String, errorTimestamp: Long) {
val recipient = recipient(context, publicKey)
if (recipient.isGroupRecipient) { return }
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
DatabaseFactory.getLokiThreadDatabase(context).addSessionRestoreDevice(threadID, publicKey)
}
}

View File

@ -1,43 +0,0 @@
package org.thoughtcrime.securesms.loki.protocol
import android.content.Context
import org.thoughtcrime.securesms.ApplicationContext
import org.session.libsession.messaging.threads.Address
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.session.libsession.messaging.threads.recipients.Recipient
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
import org.session.libsignal.libsignal.loki.SessionResetProtocol
import org.session.libsignal.libsignal.loki.SessionResetStatus
import org.session.libsignal.libsignal.protocol.PreKeySignalMessage
class SessionResetImplementation(private val context: Context) : SessionResetProtocol {
override fun getSessionResetStatus(publicKey: String): SessionResetStatus {
return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(publicKey)
}
override fun setSessionResetStatus(publicKey: String, sessionResetStatus: SessionResetStatus) {
return DatabaseFactory.getLokiThreadDatabase(context).setSessionResetStatus(publicKey, sessionResetStatus)
}
override fun onNewSessionAdopted(publicKey: String, oldSessionResetStatus: SessionResetStatus) {
if (oldSessionResetStatus == SessionResetStatus.IN_PROGRESS) {
val job = NullMessageSendJob(publicKey)
ApplicationContext.getInstance(context).jobManager.add(job)
}
val smsDB = DatabaseFactory.getSmsDatabase(context)
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
if (infoMessageID > -1) {
smsDB.markAsLokiSessionRestorationDone(infoMessageID)
}
}
override fun validatePreKeySignalMessage(publicKey: String, message: PreKeySignalMessage) {
// val preKeyRecord = DatabaseFactory.getLokiPreKeyRecordDatabase(context).getPreKeyRecord(publicKey) ?: return
// // TODO: Checking that the pre key record isn't null is causing issues when it shouldn't
// check(preKeyRecord.id == (message.preKeyId ?: -1)) { "Received a background message from an unknown source." }
}
}

View File

@ -4,7 +4,7 @@ import android.content.Context
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MessageRecord
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
object MentionManagerUtilities { object MentionManagerUtilities {

View File

@ -15,8 +15,6 @@ import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities.populat
import org.thoughtcrime.securesms.loki.utilities.MentionUtilities.highlightMentions import org.thoughtcrime.securesms.loki.utilities.MentionUtilities.highlightMentions
import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.DateUtils
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager
import java.util.* import java.util.*
class ConversationView : LinearLayout { class ConversationView : LinearLayout {

View File

@ -10,7 +10,7 @@ import android.widget.ListView
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.loki.utilities.toPx
import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.GlideRequests
import org.session.libsignal.service.loki.protocol.mentions.Mention import org.session.libsignal.service.loki.utilities.mentions.Mention
class MentionCandidateSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) { class MentionCandidateSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) {
private var mentionCandidates = listOf<Mention>() private var mentionCandidates = listOf<Mention>()

View File

@ -10,7 +10,7 @@ import kotlinx.android.synthetic.main.view_mention_candidate.view.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.GlideRequests
import org.session.libsignal.service.loki.api.opengroups.PublicChatAPI import org.session.libsignal.service.loki.api.opengroups.PublicChatAPI
import org.session.libsignal.service.loki.protocol.mentions.Mention import org.session.libsignal.service.loki.utilities.mentions.Mention
class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
var mentionCandidate = Mention("", "") var mentionCandidate = Mention("", "")

View File

@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.loki.utilities.AvatarPlaceholderGenerator
import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.GlideRequests
import org.session.libsession.messaging.threads.recipients.Recipient import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
// TODO: Look into a better way of handling different sizes. Maybe an enum (with associated values) encapsulating the different modes? // TODO: Look into a better way of handling different sizes. Maybe an enum (with associated values) encapsulating the different modes?

View File

@ -83,7 +83,6 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
Optional.absent(), Optional.absent(),
Optional.absent(), Optional.absent(),
Optional.absent(), Optional.absent(),
Optional.absent(),
Optional.absent()); Optional.absent());
database.insertSecureDecryptedMessageInbox(mediaMessage, -1); database.insertSecureDecryptedMessageInbox(mediaMessage, -1);

View File

@ -278,6 +278,12 @@ message GroupContext {
repeated string members = 4; repeated string members = 4;
optional AttachmentPointer avatar = 5; optional AttachmentPointer avatar = 5;
repeated string admins = 6; repeated string admins = 6;
// Loki - These fields are only used internally for the Android code base.
// This is so that we can differentiate adding/kicking.
// DO NOT USE WHEN SENDING MESSAGES.
repeated string newMembers = 998;
repeated string removedMembers = 999;
} }
message ContactDetails { message ContactDetails {

View File

@ -1,78 +0,0 @@
package org.session.libsignal.libsignal.loki
import org.session.libsignal.libsignal.DecryptionCallback
import org.session.libsignal.libsignal.SessionCipher
import org.session.libsignal.libsignal.SignalProtocolAddress
import org.session.libsignal.libsignal.protocol.PreKeySignalMessage
import org.session.libsignal.libsignal.protocol.SignalMessage
import org.session.libsignal.libsignal.state.SessionState
import org.session.libsignal.libsignal.state.SignalProtocolStore
/**
* A wrapper class for `SessionCipher`.
* This applies session reset logic on decryption.
*/
class LokiSessionCipher(private val protocolStore: SignalProtocolStore, private var sessionResetProtocol: SessionResetProtocol, val address: SignalProtocolAddress) : SessionCipher(protocolStore, address) {
override fun decrypt(ciphertext: PreKeySignalMessage?, callback: DecryptionCallback?): ByteArray {
// Record the current session state as it may change during decryption
val activeSession = getCurrentSessionState()
if (activeSession == null && ciphertext != null) {
sessionResetProtocol.validatePreKeySignalMessage(address.name, ciphertext)
}
val plainText = super.decrypt(ciphertext, callback)
handleSessionResetRequestIfNeeded(activeSession)
return plainText
}
override fun decrypt(ciphertext: SignalMessage?, callback: DecryptionCallback?): ByteArray {
// Record the current session state as it may change during decryption
val activeSession = getCurrentSessionState()
val plainText = super.decrypt(ciphertext, callback)
handleSessionResetRequestIfNeeded(activeSession)
return plainText
}
private fun getCurrentSessionState(): SessionState? {
val sessionRecord = protocolStore.loadSession(address)
return sessionRecord.sessionState
}
private fun handleSessionResetRequestIfNeeded(oldSession: SessionState?) {
if (oldSession == null) { return }
val publicKey = address.name
val currentSessionResetStatus = sessionResetProtocol.getSessionResetStatus(publicKey)
if (currentSessionResetStatus == SessionResetStatus.NONE) return
val currentSession = getCurrentSessionState()
if (currentSession == null || currentSession.aliceBaseKey?.contentEquals(oldSession.aliceBaseKey) != true) {
if (currentSessionResetStatus == SessionResetStatus.REQUEST_RECEIVED) {
// The other user used an old session to contact us; wait for them to switch to a new one.
restoreSession(oldSession)
} else {
// Our session reset was successful; we initiated one and got a new session back from the other user.
deleteAllSessionsExcept(currentSession)
sessionResetProtocol.setSessionResetStatus(publicKey, SessionResetStatus.NONE)
sessionResetProtocol.onNewSessionAdopted(publicKey, currentSessionResetStatus)
}
} else if (currentSessionResetStatus == SessionResetStatus.REQUEST_RECEIVED) {
// Our session reset was successful; we received a message with the same session from the other user.
deleteAllSessionsExcept(oldSession)
sessionResetProtocol.setSessionResetStatus(publicKey, SessionResetStatus.NONE)
sessionResetProtocol.onNewSessionAdopted(publicKey, currentSessionResetStatus)
}
}
private fun restoreSession(state: SessionState) {
val session = protocolStore.loadSession(address)
session.previousSessionStates.removeAll { it.aliceBaseKey?.contentEquals(state.aliceBaseKey) ?: false }
session.promoteState(state)
protocolStore.storeSession(address, session)
}
private fun deleteAllSessionsExcept(state: SessionState?) {
val sessionRecord = protocolStore.loadSession(address)
sessionRecord.removePreviousSessionStates()
sessionRecord.setState(state ?: SessionState())
protocolStore.storeSession(address, sessionRecord)
}
}

View File

@ -1,11 +0,0 @@
package org.session.libsignal.libsignal.loki
import org.session.libsignal.libsignal.protocol.PreKeySignalMessage
interface SessionResetProtocol {
fun getSessionResetStatus(publicKey: String): SessionResetStatus
fun setSessionResetStatus(publicKey: String, sessionResetStatus: SessionResetStatus)
fun validatePreKeySignalMessage(publicKey: String, message: PreKeySignalMessage)
fun onNewSessionAdopted(publicKey: String, oldSessionResetStatus: SessionResetStatus)
}

View File

@ -1,7 +0,0 @@
package org.session.libsignal.libsignal.loki
enum class SessionResetStatus(val rawValue: Int) {
NONE(0),
IN_PROGRESS(1),
REQUEST_RECEIVED(2)
}

View File

@ -24,8 +24,6 @@ import org.session.libsignal.libsignal.ecc.ECPrivateKey;
import org.session.libsignal.libsignal.ecc.ECPublicKey; import org.session.libsignal.libsignal.ecc.ECPublicKey;
import org.session.libsignal.libsignal.kdf.HKDFv3; import org.session.libsignal.libsignal.kdf.HKDFv3;
import org.session.libsignal.libsignal.loki.FallbackSessionCipher; import org.session.libsignal.libsignal.loki.FallbackSessionCipher;
import org.session.libsignal.libsignal.loki.LokiSessionCipher;
import org.session.libsignal.libsignal.loki.SessionResetProtocol;
import org.session.libsignal.libsignal.protocol.CiphertextMessage; import org.session.libsignal.libsignal.protocol.CiphertextMessage;
import org.session.libsignal.libsignal.protocol.PreKeySignalMessage; import org.session.libsignal.libsignal.protocol.PreKeySignalMessage;
import org.session.libsignal.libsignal.protocol.SignalMessage; import org.session.libsignal.libsignal.protocol.SignalMessage;
@ -51,15 +49,11 @@ import javax.crypto.spec.SecretKeySpec;
public class SealedSessionCipher { public class SealedSessionCipher {
private final SignalProtocolStore signalProtocolStore; private final SignalProtocolStore signalProtocolStore;
private final SessionResetProtocol sessionResetProtocol;
private final SignalProtocolAddress localAddress; private final SignalProtocolAddress localAddress;
public SealedSessionCipher(SignalProtocolStore signalProtocolStore, public SealedSessionCipher(SignalProtocolStore signalProtocolStore, SignalProtocolAddress localAddress)
SessionResetProtocol sessionResetProtocol,
SignalProtocolAddress localAddress)
{ {
this.signalProtocolStore = signalProtocolStore; this.signalProtocolStore = signalProtocolStore;
this.sessionResetProtocol = sessionResetProtocol;
this.localAddress = localAddress; this.localAddress = localAddress;
} }
@ -201,8 +195,8 @@ public class SealedSessionCipher {
SignalProtocolAddress sender = new SignalProtocolAddress(message.getSenderCertificate().getSender(), message.getSenderCertificate().getSenderDeviceId()); SignalProtocolAddress sender = new SignalProtocolAddress(message.getSenderCertificate().getSender(), message.getSenderCertificate().getSenderDeviceId());
switch (message.getType()) { switch (message.getType()) {
case CiphertextMessage.WHISPER_TYPE: return new LokiSessionCipher(signalProtocolStore, sessionResetProtocol, sender).decrypt(new SignalMessage(message.getContent())); case CiphertextMessage.WHISPER_TYPE: return new SessionCipher(signalProtocolStore, sender).decrypt(new SignalMessage(message.getContent()));
case CiphertextMessage.PREKEY_TYPE: return new LokiSessionCipher(signalProtocolStore, sessionResetProtocol, sender).decrypt(new PreKeySignalMessage(message.getContent())); case CiphertextMessage.PREKEY_TYPE: return new SessionCipher(signalProtocolStore, sender).decrypt(new PreKeySignalMessage(message.getContent()));
case CiphertextMessage.FALLBACK_MESSAGE_TYPE: { case CiphertextMessage.FALLBACK_MESSAGE_TYPE: {
try { try {
byte[] privateKey = signalProtocolStore.getIdentityKeyPair().getPrivateKey().serialize(); byte[] privateKey = signalProtocolStore.getIdentityKeyPair().getPrivateKey().serialize();

View File

@ -6,12 +6,10 @@
package org.session.libsignal.service.api; package org.session.libsignal.service.api;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.session.libsignal.libsignal.ecc.ECKeyPair; import org.session.libsignal.libsignal.ecc.ECKeyPair;
import org.session.libsignal.utilities.logging.Log; import org.session.libsignal.utilities.logging.Log;
import org.session.libsignal.libsignal.loki.SessionResetProtocol;
import org.session.libsignal.libsignal.state.SignalProtocolStore; import org.session.libsignal.libsignal.state.SignalProtocolStore;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.crypto.AttachmentCipherOutputStream; import org.session.libsignal.service.api.crypto.AttachmentCipherOutputStream;
@ -67,24 +65,20 @@ import org.session.libsignal.service.loki.database.LokiOpenGroupDatabaseProtocol
import org.session.libsignal.service.loki.database.LokiPreKeyBundleDatabaseProtocol; import org.session.libsignal.service.loki.database.LokiPreKeyBundleDatabaseProtocol;
import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol; import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol;
import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol; import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities; import org.session.libsignal.service.loki.utilities.TTLUtilities;
import org.session.libsignal.service.loki.protocol.sessionmanagement.SessionManagementProtocol;
import org.session.libsignal.service.loki.utilities.Broadcaster; import org.session.libsignal.service.loki.utilities.Broadcaster;
import org.session.libsignal.service.loki.utilities.HexEncodingKt; import org.session.libsignal.service.loki.utilities.HexEncodingKt;
import org.session.libsignal.service.loki.utilities.PlaintextOutputStreamFactory; import org.session.libsignal.service.loki.utilities.PlaintextOutputStreamFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import kotlin.Unit; import kotlin.Unit;
@ -100,10 +94,8 @@ public class SignalServiceMessageSender {
private static final String TAG = SignalServiceMessageSender.class.getSimpleName(); private static final String TAG = SignalServiceMessageSender.class.getSimpleName();
private final PushServiceSocket socket;
private final SignalProtocolStore store; private final SignalProtocolStore store;
private final SignalServiceAddress localAddress; private final SignalServiceAddress localAddress;
private final Optional<EventListener> eventListener;
private final AtomicReference<Optional<SignalServiceMessagePipe>> pipe; private final AtomicReference<Optional<SignalServiceMessagePipe>> pipe;
private final AtomicReference<Optional<SignalServiceMessagePipe>> unidentifiedPipe; private final AtomicReference<Optional<SignalServiceMessagePipe>> unidentifiedPipe;
@ -113,9 +105,7 @@ public class SignalServiceMessageSender {
private final LokiAPIDatabaseProtocol apiDatabase; private final LokiAPIDatabaseProtocol apiDatabase;
private final LokiThreadDatabaseProtocol threadDatabase; private final LokiThreadDatabaseProtocol threadDatabase;
private final LokiMessageDatabaseProtocol messageDatabase; private final LokiMessageDatabaseProtocol messageDatabase;
private final LokiPreKeyBundleDatabaseProtocol preKeyBundleDatabase;
private final SessionProtocol sessionProtocolImpl; private final SessionProtocol sessionProtocolImpl;
private final SessionResetProtocol sessionResetImpl;
private final LokiUserDatabaseProtocol userDatabase; private final LokiUserDatabaseProtocol userDatabase;
private final LokiOpenGroupDatabaseProtocol openGroupDatabase; private final LokiOpenGroupDatabaseProtocol openGroupDatabase;
private final Broadcaster broadcaster; private final Broadcaster broadcaster;
@ -123,65 +113,48 @@ public class SignalServiceMessageSender {
/** /**
* Construct a SignalServiceMessageSender. * Construct a SignalServiceMessageSender.
* *
* @param urls The URL of the Signal Service.
* @param user The Signal Service username (eg phone number). * @param user The Signal Service username (eg phone number).
* @param password The Signal Service user password. * @param password The Signal Service user password.
* @param store The SignalProtocolStore. * @param store The SignalProtocolStore.
* @param eventListener An optional event listener, which fires whenever sessions are
* setup or torn down for a recipient.
*/ */
public SignalServiceMessageSender(SignalServiceConfiguration urls, public SignalServiceMessageSender(String user, String password,
String user, String password,
SignalProtocolStore store, SignalProtocolStore store,
String userAgent,
Optional<SignalServiceMessagePipe> pipe, Optional<SignalServiceMessagePipe> pipe,
Optional<SignalServiceMessagePipe> unidentifiedPipe, Optional<SignalServiceMessagePipe> unidentifiedPipe,
Optional<EventListener> eventListener,
String userPublicKey, String userPublicKey,
LokiAPIDatabaseProtocol apiDatabase, LokiAPIDatabaseProtocol apiDatabase,
LokiThreadDatabaseProtocol threadDatabase, LokiThreadDatabaseProtocol threadDatabase,
LokiMessageDatabaseProtocol messageDatabase, LokiMessageDatabaseProtocol messageDatabase,
LokiPreKeyBundleDatabaseProtocol preKeyBundleDatabase,
SessionProtocol sessionProtocolImpl, SessionProtocol sessionProtocolImpl,
SessionResetProtocol sessionResetImpl,
LokiUserDatabaseProtocol userDatabase, LokiUserDatabaseProtocol userDatabase,
LokiOpenGroupDatabaseProtocol openGroupDatabase, LokiOpenGroupDatabaseProtocol openGroupDatabase,
Broadcaster broadcaster) Broadcaster broadcaster)
{ {
this(urls, new StaticCredentialsProvider(user, password, null), store, userAgent, pipe, unidentifiedPipe, eventListener, userPublicKey, apiDatabase, threadDatabase, messageDatabase, preKeyBundleDatabase, sessionProtocolImpl, sessionResetImpl, userDatabase, openGroupDatabase, broadcaster); this(new StaticCredentialsProvider(user, password, null), store, pipe, unidentifiedPipe, userPublicKey, apiDatabase, threadDatabase, messageDatabase, sessionProtocolImpl, userDatabase, openGroupDatabase, broadcaster);
} }
public SignalServiceMessageSender(SignalServiceConfiguration urls, public SignalServiceMessageSender(CredentialsProvider credentialsProvider,
CredentialsProvider credentialsProvider,
SignalProtocolStore store, SignalProtocolStore store,
String userAgent,
Optional<SignalServiceMessagePipe> pipe, Optional<SignalServiceMessagePipe> pipe,
Optional<SignalServiceMessagePipe> unidentifiedPipe, Optional<SignalServiceMessagePipe> unidentifiedPipe,
Optional<EventListener> eventListener,
String userPublicKey, String userPublicKey,
LokiAPIDatabaseProtocol apiDatabase, LokiAPIDatabaseProtocol apiDatabase,
LokiThreadDatabaseProtocol threadDatabase, LokiThreadDatabaseProtocol threadDatabase,
LokiMessageDatabaseProtocol messageDatabase, LokiMessageDatabaseProtocol messageDatabase,
LokiPreKeyBundleDatabaseProtocol preKeyBundleDatabase,
SessionProtocol sessionProtocolImpl, SessionProtocol sessionProtocolImpl,
SessionResetProtocol sessionResetImpl,
LokiUserDatabaseProtocol userDatabase, LokiUserDatabaseProtocol userDatabase,
LokiOpenGroupDatabaseProtocol openGroupDatabase, LokiOpenGroupDatabaseProtocol openGroupDatabase,
Broadcaster broadcaster) Broadcaster broadcaster)
{ {
this.socket = new PushServiceSocket(urls, credentialsProvider, userAgent);
this.store = store; this.store = store;
this.localAddress = new SignalServiceAddress(credentialsProvider.getUser()); this.localAddress = new SignalServiceAddress(credentialsProvider.getUser());
this.pipe = new AtomicReference<>(pipe); this.pipe = new AtomicReference<>(pipe);
this.unidentifiedPipe = new AtomicReference<>(unidentifiedPipe); this.unidentifiedPipe = new AtomicReference<>(unidentifiedPipe);
this.eventListener = eventListener;
this.userPublicKey = userPublicKey; this.userPublicKey = userPublicKey;
this.apiDatabase = apiDatabase; this.apiDatabase = apiDatabase;
this.threadDatabase = threadDatabase; this.threadDatabase = threadDatabase;
this.messageDatabase = messageDatabase; this.messageDatabase = messageDatabase;
this.preKeyBundleDatabase = preKeyBundleDatabase;
this.sessionProtocolImpl = sessionProtocolImpl; this.sessionProtocolImpl = sessionProtocolImpl;
this.sessionResetImpl = sessionResetImpl;
this.userDatabase = userDatabase; this.userDatabase = userDatabase;
this.openGroupDatabase = openGroupDatabase; this.openGroupDatabase = openGroupDatabase;
this.broadcaster = broadcaster; this.broadcaster = broadcaster;

View File

@ -10,31 +10,11 @@ import com.google.protobuf.InvalidProtocolBufferException;
import org.session.libsignal.libsignal.ecc.ECKeyPair; import org.session.libsignal.libsignal.ecc.ECKeyPair;
import org.session.libsignal.metadata.InvalidMetadataMessageException; import org.session.libsignal.metadata.InvalidMetadataMessageException;
import org.session.libsignal.metadata.InvalidMetadataVersionException;
import org.session.libsignal.metadata.ProtocolDuplicateMessageException;
import org.session.libsignal.metadata.ProtocolInvalidKeyException;
import org.session.libsignal.metadata.ProtocolInvalidKeyIdException;
import org.session.libsignal.metadata.ProtocolInvalidMessageException; import org.session.libsignal.metadata.ProtocolInvalidMessageException;
import org.session.libsignal.metadata.ProtocolInvalidVersionException;
import org.session.libsignal.metadata.ProtocolLegacyMessageException;
import org.session.libsignal.metadata.ProtocolNoSessionException;
import org.session.libsignal.metadata.ProtocolUntrustedIdentityException;
import org.session.libsignal.metadata.SealedSessionCipher; import org.session.libsignal.metadata.SealedSessionCipher;
import org.session.libsignal.metadata.SelfSendException;
import org.session.libsignal.libsignal.DuplicateMessageException;
import org.session.libsignal.libsignal.InvalidKeyException;
import org.session.libsignal.libsignal.InvalidKeyIdException;
import org.session.libsignal.libsignal.InvalidMessageException; import org.session.libsignal.libsignal.InvalidMessageException;
import org.session.libsignal.libsignal.InvalidVersionException;
import org.session.libsignal.libsignal.LegacyMessageException;
import org.session.libsignal.libsignal.NoSessionException;
import org.session.libsignal.libsignal.SessionCipher; import org.session.libsignal.libsignal.SessionCipher;
import org.session.libsignal.libsignal.SignalProtocolAddress; import org.session.libsignal.libsignal.SignalProtocolAddress;
import org.session.libsignal.libsignal.UntrustedIdentityException;
import org.session.libsignal.libsignal.loki.LokiSessionCipher;
import org.session.libsignal.libsignal.loki.SessionResetProtocol;
import org.session.libsignal.libsignal.protocol.PreKeySignalMessage;
import org.session.libsignal.libsignal.protocol.SignalMessage;
import org.session.libsignal.libsignal.state.SignalProtocolStore; import org.session.libsignal.libsignal.state.SignalProtocolStore;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.messages.SignalServiceAttachment; import org.session.libsignal.service.api.messages.SignalServiceAttachment;
@ -60,7 +40,6 @@ import org.session.libsignal.service.loki.api.crypto.SessionProtocol;
import org.session.libsignal.service.loki.api.crypto.SessionProtocolUtilities; import org.session.libsignal.service.loki.api.crypto.SessionProtocolUtilities;
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol; import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol;
import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -77,19 +56,16 @@ public class SignalServiceCipher {
private static final String TAG = SignalServiceCipher.class.getSimpleName(); private static final String TAG = SignalServiceCipher.class.getSimpleName();
private final SignalProtocolStore signalProtocolStore; private final SignalProtocolStore signalProtocolStore;
private final SessionResetProtocol sessionResetProtocol;
private final SignalServiceAddress localAddress; private final SignalServiceAddress localAddress;
private final SessionProtocol sessionProtocolImpl; private final SessionProtocol sessionProtocolImpl;
private final LokiAPIDatabaseProtocol apiDB; private final LokiAPIDatabaseProtocol apiDB;
public SignalServiceCipher(SignalServiceAddress localAddress, public SignalServiceCipher(SignalServiceAddress localAddress,
SignalProtocolStore signalProtocolStore, SignalProtocolStore signalProtocolStore,
SessionResetProtocol sessionResetProtocol,
SessionProtocol sessionProtocolImpl, SessionProtocol sessionProtocolImpl,
LokiAPIDatabaseProtocol apiDB) LokiAPIDatabaseProtocol apiDB)
{ {
this.signalProtocolStore = signalProtocolStore; this.signalProtocolStore = signalProtocolStore;
this.sessionResetProtocol = sessionResetProtocol;
this.localAddress = localAddress; this.localAddress = localAddress;
this.sessionProtocolImpl = sessionProtocolImpl; this.sessionProtocolImpl = sessionProtocolImpl;
this.apiDB = apiDB; this.apiDB = apiDB;
@ -160,8 +136,8 @@ public class SignalServiceCipher {
protected Plaintext decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) throws InvalidMetadataMessageException protected Plaintext decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) throws InvalidMetadataMessageException
{ {
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSource(), envelope.getSourceDevice()); SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSource(), envelope.getSourceDevice());
SessionCipher sessionCipher = new LokiSessionCipher(signalProtocolStore, sessionResetProtocol, sourceAddress); SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);
SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, sessionResetProtocol, new SignalProtocolAddress(localAddress.getNumber(), 1)); SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, new SignalProtocolAddress(localAddress.getNumber(), 1));
byte[] paddedMessage; byte[] paddedMessage;
Metadata metadata; Metadata metadata;

View File

@ -7,9 +7,7 @@
package org.session.libsignal.service.api.messages; package org.session.libsignal.service.api.messages;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.messages.calls.SignalServiceCallMessage;
import org.session.libsignal.service.internal.push.SignalServiceProtos; import org.session.libsignal.service.internal.push.SignalServiceProtos;
import org.session.libsignal.service.loki.protocol.sessionmanagement.PreKeyBundleMessage;
public class SignalServiceContent { public class SignalServiceContent {
private final String sender; private final String sender;
@ -24,7 +22,6 @@ public class SignalServiceContent {
// Loki // Loki
public Optional<SignalServiceProtos.Content> configurationMessageProto = Optional.absent(); public Optional<SignalServiceProtos.Content> configurationMessageProto = Optional.absent();
public Optional<PreKeyBundleMessage> preKeyBundleMessage = Optional.absent();
public Optional<String> senderDisplayName = Optional.absent(); public Optional<String> senderDisplayName = Optional.absent();
public Optional<String> senderProfilePictureURL = Optional.absent(); public Optional<String> senderProfilePictureURL = Optional.absent();

View File

@ -11,7 +11,7 @@ import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.messages.shared.SharedContact; import org.session.libsignal.service.api.messages.shared.SharedContact;
import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsignal.service.api.push.SignalServiceAddress;
import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage; import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities; import org.session.libsignal.service.loki.utilities.TTLUtilities;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;

View File

@ -1,6 +1,6 @@
package org.session.libsignal.service.api.messages; package org.session.libsignal.service.api.messages;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities; import org.session.libsignal.service.loki.utilities.TTLUtilities;
public class SignalServiceNullMessage { public class SignalServiceNullMessage {

View File

@ -1,7 +1,7 @@
package org.session.libsignal.service.api.messages; package org.session.libsignal.service.api.messages;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities; import org.session.libsignal.service.loki.utilities.TTLUtilities;
import java.util.List; import java.util.List;

View File

@ -1,7 +1,6 @@
package org.session.libsignal.service.api.messages; package org.session.libsignal.service.api.messages;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.loki.utilities.TTLUtilities;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities;
public class SignalServiceTypingMessage { public class SignalServiceTypingMessage {

View File

@ -1,7 +1,7 @@
package org.session.libsignal.service.api.messages.calls; package org.session.libsignal.service.api.messages.calls;
import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities; import org.session.libsignal.service.loki.utilities.TTLUtilities;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;

View File

@ -24483,6 +24483,70 @@ public final class SignalServiceProtos {
*/ */
com.google.protobuf.ByteString com.google.protobuf.ByteString
getAdminsBytes(int index); getAdminsBytes(int index);
// repeated string newMembers = 998;
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
java.util.List<java.lang.String>
getNewMembersList();
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
int getNewMembersCount();
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
java.lang.String getNewMembers(int index);
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
com.google.protobuf.ByteString
getNewMembersBytes(int index);
// repeated string removedMembers = 999;
/**
* <code>repeated string removedMembers = 999;</code>
*/
java.util.List<java.lang.String>
getRemovedMembersList();
/**
* <code>repeated string removedMembers = 999;</code>
*/
int getRemovedMembersCount();
/**
* <code>repeated string removedMembers = 999;</code>
*/
java.lang.String getRemovedMembers(int index);
/**
* <code>repeated string removedMembers = 999;</code>
*/
com.google.protobuf.ByteString
getRemovedMembersBytes(int index);
} }
/** /**
* Protobuf type {@code signalservice.GroupContext} * Protobuf type {@code signalservice.GroupContext}
@ -24585,6 +24649,22 @@ public final class SignalServiceProtos {
admins_.add(input.readBytes()); admins_.add(input.readBytes());
break; break;
} }
case 7986: {
if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
newMembers_ = new com.google.protobuf.LazyStringArrayList();
mutable_bitField0_ |= 0x00000040;
}
newMembers_.add(input.readBytes());
break;
}
case 7994: {
if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
removedMembers_ = new com.google.protobuf.LazyStringArrayList();
mutable_bitField0_ |= 0x00000080;
}
removedMembers_.add(input.readBytes());
break;
}
} }
} }
} catch (com.google.protobuf.InvalidProtocolBufferException e) { } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -24599,6 +24679,12 @@ public final class SignalServiceProtos {
if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) { if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) {
admins_ = new com.google.protobuf.UnmodifiableLazyStringList(admins_); admins_ = new com.google.protobuf.UnmodifiableLazyStringList(admins_);
} }
if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
newMembers_ = new com.google.protobuf.UnmodifiableLazyStringList(newMembers_);
}
if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
removedMembers_ = new com.google.protobuf.UnmodifiableLazyStringList(removedMembers_);
}
this.unknownFields = unknownFields.build(); this.unknownFields = unknownFields.build();
makeExtensionsImmutable(); makeExtensionsImmutable();
} }
@ -24913,6 +24999,90 @@ public final class SignalServiceProtos {
return admins_.getByteString(index); return admins_.getByteString(index);
} }
// repeated string newMembers = 998;
public static final int NEWMEMBERS_FIELD_NUMBER = 998;
private com.google.protobuf.LazyStringList newMembers_;
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public java.util.List<java.lang.String>
getNewMembersList() {
return newMembers_;
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public int getNewMembersCount() {
return newMembers_.size();
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public java.lang.String getNewMembers(int index) {
return newMembers_.get(index);
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public com.google.protobuf.ByteString
getNewMembersBytes(int index) {
return newMembers_.getByteString(index);
}
// repeated string removedMembers = 999;
public static final int REMOVEDMEMBERS_FIELD_NUMBER = 999;
private com.google.protobuf.LazyStringList removedMembers_;
/**
* <code>repeated string removedMembers = 999;</code>
*/
public java.util.List<java.lang.String>
getRemovedMembersList() {
return removedMembers_;
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public int getRemovedMembersCount() {
return removedMembers_.size();
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public java.lang.String getRemovedMembers(int index) {
return removedMembers_.get(index);
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public com.google.protobuf.ByteString
getRemovedMembersBytes(int index) {
return removedMembers_.getByteString(index);
}
private void initFields() { private void initFields() {
id_ = com.google.protobuf.ByteString.EMPTY; id_ = com.google.protobuf.ByteString.EMPTY;
type_ = org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext.Type.UNKNOWN; type_ = org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext.Type.UNKNOWN;
@ -24920,6 +25090,8 @@ public final class SignalServiceProtos {
members_ = com.google.protobuf.LazyStringArrayList.EMPTY; members_ = com.google.protobuf.LazyStringArrayList.EMPTY;
avatar_ = org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer.getDefaultInstance(); avatar_ = org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer.getDefaultInstance();
admins_ = com.google.protobuf.LazyStringArrayList.EMPTY; admins_ = com.google.protobuf.LazyStringArrayList.EMPTY;
newMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
removedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@ -24951,6 +25123,12 @@ public final class SignalServiceProtos {
for (int i = 0; i < admins_.size(); i++) { for (int i = 0; i < admins_.size(); i++) {
output.writeBytes(6, admins_.getByteString(i)); output.writeBytes(6, admins_.getByteString(i));
} }
for (int i = 0; i < newMembers_.size(); i++) {
output.writeBytes(998, newMembers_.getByteString(i));
}
for (int i = 0; i < removedMembers_.size(); i++) {
output.writeBytes(999, removedMembers_.getByteString(i));
}
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@ -24994,6 +25172,24 @@ public final class SignalServiceProtos {
size += dataSize; size += dataSize;
size += 1 * getAdminsList().size(); size += 1 * getAdminsList().size();
} }
{
int dataSize = 0;
for (int i = 0; i < newMembers_.size(); i++) {
dataSize += com.google.protobuf.CodedOutputStream
.computeBytesSizeNoTag(newMembers_.getByteString(i));
}
size += dataSize;
size += 2 * getNewMembersList().size();
}
{
int dataSize = 0;
for (int i = 0; i < removedMembers_.size(); i++) {
dataSize += com.google.protobuf.CodedOutputStream
.computeBytesSizeNoTag(removedMembers_.getByteString(i));
}
size += dataSize;
size += 2 * getRemovedMembersList().size();
}
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@ -25127,6 +25323,10 @@ public final class SignalServiceProtos {
bitField0_ = (bitField0_ & ~0x00000010); bitField0_ = (bitField0_ & ~0x00000010);
admins_ = com.google.protobuf.LazyStringArrayList.EMPTY; admins_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000020); bitField0_ = (bitField0_ & ~0x00000020);
newMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000040);
removedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000080);
return this; return this;
} }
@ -25187,6 +25387,18 @@ public final class SignalServiceProtos {
bitField0_ = (bitField0_ & ~0x00000020); bitField0_ = (bitField0_ & ~0x00000020);
} }
result.admins_ = admins_; result.admins_ = admins_;
if (((bitField0_ & 0x00000040) == 0x00000040)) {
newMembers_ = new com.google.protobuf.UnmodifiableLazyStringList(
newMembers_);
bitField0_ = (bitField0_ & ~0x00000040);
}
result.newMembers_ = newMembers_;
if (((bitField0_ & 0x00000080) == 0x00000080)) {
removedMembers_ = new com.google.protobuf.UnmodifiableLazyStringList(
removedMembers_);
bitField0_ = (bitField0_ & ~0x00000080);
}
result.removedMembers_ = removedMembers_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
return result; return result;
@ -25237,6 +25449,26 @@ public final class SignalServiceProtos {
} }
onChanged(); onChanged();
} }
if (!other.newMembers_.isEmpty()) {
if (newMembers_.isEmpty()) {
newMembers_ = other.newMembers_;
bitField0_ = (bitField0_ & ~0x00000040);
} else {
ensureNewMembersIsMutable();
newMembers_.addAll(other.newMembers_);
}
onChanged();
}
if (!other.removedMembers_.isEmpty()) {
if (removedMembers_.isEmpty()) {
removedMembers_ = other.removedMembers_;
bitField0_ = (bitField0_ & ~0x00000080);
} else {
ensureRemovedMembersIsMutable();
removedMembers_.addAll(other.removedMembers_);
}
onChanged();
}
this.mergeUnknownFields(other.getUnknownFields()); this.mergeUnknownFields(other.getUnknownFields());
return this; return this;
} }
@ -25745,6 +25977,246 @@ public final class SignalServiceProtos {
return this; return this;
} }
// repeated string newMembers = 998;
private com.google.protobuf.LazyStringList newMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
private void ensureNewMembersIsMutable() {
if (!((bitField0_ & 0x00000040) == 0x00000040)) {
newMembers_ = new com.google.protobuf.LazyStringArrayList(newMembers_);
bitField0_ |= 0x00000040;
}
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public java.util.List<java.lang.String>
getNewMembersList() {
return java.util.Collections.unmodifiableList(newMembers_);
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public int getNewMembersCount() {
return newMembers_.size();
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public java.lang.String getNewMembers(int index) {
return newMembers_.get(index);
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public com.google.protobuf.ByteString
getNewMembersBytes(int index) {
return newMembers_.getByteString(index);
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public Builder setNewMembers(
int index, java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
ensureNewMembersIsMutable();
newMembers_.set(index, value);
onChanged();
return this;
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public Builder addNewMembers(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
ensureNewMembersIsMutable();
newMembers_.add(value);
onChanged();
return this;
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public Builder addAllNewMembers(
java.lang.Iterable<java.lang.String> values) {
ensureNewMembersIsMutable();
super.addAll(values, newMembers_);
onChanged();
return this;
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public Builder clearNewMembers() {
newMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000040);
onChanged();
return this;
}
/**
* <code>repeated string newMembers = 998;</code>
*
* <pre>
* Loki - These fields are only used internally for the Android code base.
* This is so that we can differentiate adding/kicking.
* DO NOT USE WHEN SENDING MESSAGES.
* </pre>
*/
public Builder addNewMembersBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
ensureNewMembersIsMutable();
newMembers_.add(value);
onChanged();
return this;
}
// repeated string removedMembers = 999;
private com.google.protobuf.LazyStringList removedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
private void ensureRemovedMembersIsMutable() {
if (!((bitField0_ & 0x00000080) == 0x00000080)) {
removedMembers_ = new com.google.protobuf.LazyStringArrayList(removedMembers_);
bitField0_ |= 0x00000080;
}
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public java.util.List<java.lang.String>
getRemovedMembersList() {
return java.util.Collections.unmodifiableList(removedMembers_);
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public int getRemovedMembersCount() {
return removedMembers_.size();
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public java.lang.String getRemovedMembers(int index) {
return removedMembers_.get(index);
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public com.google.protobuf.ByteString
getRemovedMembersBytes(int index) {
return removedMembers_.getByteString(index);
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public Builder setRemovedMembers(
int index, java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
ensureRemovedMembersIsMutable();
removedMembers_.set(index, value);
onChanged();
return this;
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public Builder addRemovedMembers(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
ensureRemovedMembersIsMutable();
removedMembers_.add(value);
onChanged();
return this;
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public Builder addAllRemovedMembers(
java.lang.Iterable<java.lang.String> values) {
ensureRemovedMembersIsMutable();
super.addAll(values, removedMembers_);
onChanged();
return this;
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public Builder clearRemovedMembers() {
removedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000080);
onChanged();
return this;
}
/**
* <code>repeated string removedMembers = 999;</code>
*/
public Builder addRemovedMembersBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
ensureRemovedMembersIsMutable();
removedMembers_.add(value);
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:signalservice.GroupContext) // @@protoc_insertion_point(builder_scope:signalservice.GroupContext)
} }
@ -30486,28 +30958,30 @@ public final class SignalServiceProtos {
"thumbnail\030\005 \001(\014\022\016\n\006digest\030\006 \001(\014\022\020\n\010fileN" + "thumbnail\030\005 \001(\014\022\016\n\006digest\030\006 \001(\014\022\020\n\010fileN" +
"ame\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n\005width\030\t \001(\r\022" + "ame\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n\005width\030\t \001(\r\022" +
"\016\n\006height\030\n \001(\r\022\017\n\007caption\030\013 \001(\t\022\013\n\003url\030", "\016\n\006height\030\n \001(\r\022\017\n\007caption\030\013 \001(\t\022\013\n\003url\030",
"e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MESSAGE\020\001\"\365\001\n\014Gr" + "e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MESSAGE\020\001\"\243\002\n\014Gr" +
"oupContext\022\n\n\002id\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .s" + "oupContext\022\n\n\002id\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .s" +
"ignalservice.GroupContext.Type\022\014\n\004name\030\003" + "ignalservice.GroupContext.Type\022\014\n\004name\030\003" +
" \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 ." + " \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 ." +
"signalservice.AttachmentPointer\022\016\n\006admin" + "signalservice.AttachmentPointer\022\016\n\006admin" +
"s\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UPDATE\020\001" + "s\030\006 \003(\t\022\023\n\nnewMembers\030\346\007 \003(\t\022\027\n\016removedM" +
"\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST_INFO\020" + "embers\030\347\007 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UP" +
"\004\"\356\001\n\016ContactDetails\022\016\n\006number\030\001 \001(\t\022\014\n\004" + "DATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST" +
"name\030\002 \001(\t\0224\n\006avatar\030\003 \001(\0132$.signalservi" + "_INFO\020\004\"\356\001\n\016ContactDetails\022\016\n\006number\030\001 \001" +
"ce.ContactDetails.Avatar\022\r\n\005color\030\004 \001(\t\022", "(\t\022\014\n\004name\030\002 \001(\t\0224\n\006avatar\030\003 \001(\0132$.signa",
"\022\n\nprofileKey\030\006 \001(\014\022\017\n\007blocked\030\007 \001(\010\022\023\n\013" + "lservice.ContactDetails.Avatar\022\r\n\005color\030" +
"expireTimer\030\010 \001(\r\022\020\n\010nickname\030e \001(\t\032-\n\006A" + "\004 \001(\t\022\022\n\nprofileKey\030\006 \001(\014\022\017\n\007blocked\030\007 \001" +
"vatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006length\030\002 \001" + "(\010\022\023\n\013expireTimer\030\010 \001(\r\022\020\n\010nickname\030e \001(" +
"(\r\"\367\001\n\014GroupDetails\022\n\n\002id\030\001 \001(\014\022\014\n\004name\030" + "\t\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006leng" +
"\002 \001(\t\022\017\n\007members\030\003 \003(\t\0222\n\006avatar\030\004 \001(\0132\"" + "th\030\002 \001(\r\"\367\001\n\014GroupDetails\022\n\n\002id\030\001 \001(\014\022\014\n" +
".signalservice.GroupDetails.Avatar\022\024\n\006ac" + "\004name\030\002 \001(\t\022\017\n\007members\030\003 \003(\t\0222\n\006avatar\030\004" +
"tive\030\005 \001(\010:\004true\022\023\n\013expireTimer\030\006 \001(\r\022\r\n" + " \001(\0132\".signalservice.GroupDetails.Avatar" +
"\005color\030\007 \001(\t\022\017\n\007blocked\030\010 \001(\010\022\016\n\006admins\030" + "\022\024\n\006active\030\005 \001(\010:\004true\022\023\n\013expireTimer\030\006 " +
"\t \003(\t\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006" + "\001(\r\022\r\n\005color\030\007 \001(\t\022\017\n\007blocked\030\010 \001(\010\022\016\n\006a" +
"length\030\002 \001(\r\"\"\n\016PublicChatInfo\022\020\n\010server", "dmins\030\t \003(\t\032-\n\006Avatar\022\023\n\013contentType\030\001 \001",
"ID\030\001 \001(\004BB\n+org.session.libsignal.servic" + "(\t\022\016\n\006length\030\002 \001(\r\"\"\n\016PublicChatInfo\022\020\n\010" +
"e.internal.pushB\023SignalServiceProtos" "serverID\030\001 \001(\004BB\n+org.session.libsignal." +
"service.internal.pushB\023SignalServiceProt" +
"os"
}; };
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -30651,7 +31125,7 @@ public final class SignalServiceProtos {
internal_static_signalservice_GroupContext_fieldAccessorTable = new internal_static_signalservice_GroupContext_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_signalservice_GroupContext_descriptor, internal_static_signalservice_GroupContext_descriptor,
new java.lang.String[] { "Id", "Type", "Name", "Members", "Avatar", "Admins", }); new java.lang.String[] { "Id", "Type", "Name", "Members", "Avatar", "Admins", "NewMembers", "RemovedMembers", });
internal_static_signalservice_ContactDetails_descriptor = internal_static_signalservice_ContactDetails_descriptor =
getDescriptor().getMessageTypes().get(10); getDescriptor().getMessageTypes().get(10);
internal_static_signalservice_ContactDetails_fieldAccessorTable = new internal_static_signalservice_ContactDetails_fieldAccessorTable = new

View File

@ -5,7 +5,7 @@ import nl.komponents.kovenant.deferred
import org.session.libsignal.utilities.logging.Log import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Base64
import org.session.libsignal.service.loki.api.crypto.ProofOfWork import org.session.libsignal.service.loki.api.crypto.ProofOfWork
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities import org.session.libsignal.service.loki.utilities.TTLUtilities
import org.session.libsignal.utilities.ThreadUtils import org.session.libsignal.utilities.ThreadUtils
import org.session.libsignal.service.loki.utilities.prettifiedDescription import org.session.libsignal.service.loki.utilities.prettifiedDescription

View File

@ -1,24 +0,0 @@
package org.session.libsignal.service.loki.protocol.meta
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol
public class SessionMetaProtocol(private val apiDatabase: LokiAPIDatabaseProtocol, private val userPublicKey: String) {
// region Initialization
companion object {
public lateinit var shared: SessionMetaProtocol
public fun configureIfNeeded(apiDatabase: LokiAPIDatabaseProtocol, userPublicKey: String) {
if (::shared.isInitialized) { return; }
shared = SessionMetaProtocol(apiDatabase, userPublicKey)
}
}
// endregion
// region Utilities
public fun isNoteToSelf(publicKey: String): Boolean {
return userPublicKey == publicKey // return MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey).contains(publicKey)
}
// endregion
}

View File

@ -1,23 +0,0 @@
package org.session.libsignal.service.loki.protocol.sessionmanagement
import org.session.libsignal.libsignal.IdentityKey
import org.session.libsignal.libsignal.ecc.Curve
import org.session.libsignal.libsignal.state.PreKeyBundle
data class PreKeyBundleMessage(
val identityKey: ByteArray,
val deviceID: Int,
val preKeyID: Int,
val signedPreKeyID: Int,
val preKey: ByteArray,
val signedPreKey: ByteArray,
val signedPreKeySignature: ByteArray
) {
constructor(preKeyBundle: PreKeyBundle) : this(preKeyBundle.identityKey.serialize(), preKeyBundle.deviceId, preKeyBundle.preKeyId,
preKeyBundle.signedPreKeyId, preKeyBundle.preKey.serialize(), preKeyBundle.signedPreKey.serialize(), preKeyBundle.signedPreKeySignature)
fun getPreKeyBundle(registrationID: Int): PreKeyBundle {
return PreKeyBundle(registrationID, deviceID, preKeyID, Curve.decodePoint(preKey, 0), signedPreKeyID, Curve.decodePoint(signedPreKey, 0), signedPreKeySignature, IdentityKey(identityKey, 0))
}
}

View File

@ -1,53 +0,0 @@
package org.session.libsignal.service.loki.protocol.sessionmanagement
import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.libsignal.loki.SessionResetProtocol
import org.session.libsignal.libsignal.loki.SessionResetStatus
import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.SignalServiceMessageSender
import org.session.libsignal.service.api.push.SignalServiceAddress
public class SessionManagementProtocol(private val sessionResetImpl: SessionResetProtocol, private val delegate: SessionManagementProtocolDelegate) {
// region Initialization
companion object {
public lateinit var shared: SessionManagementProtocol
public fun configureIfNeeded(sessionResetImpl: SessionResetProtocol, delegate: SessionManagementProtocolDelegate) {
if (::shared.isInitialized) { return; }
shared = SessionManagementProtocol(sessionResetImpl, delegate)
}
}
// endregion
// region Sending
/**
* Called after an end session message is sent.
*/
public fun setSessionResetStatusToInProgressIfNeeded(recipient: SignalServiceAddress, eventListener: Optional<SignalServiceMessageSender.EventListener>) {
val publicKey = recipient.number
val sessionResetStatus = sessionResetImpl.getSessionResetStatus(publicKey)
if (sessionResetStatus == SessionResetStatus.REQUEST_RECEIVED) { return }
Log.d("Loki", "Starting session reset")
sessionResetImpl.setSessionResetStatus(publicKey, SessionResetStatus.IN_PROGRESS)
if (!eventListener.isPresent) { return }
eventListener.get().onSecurityEvent(recipient)
}
public fun repairSessionIfNeeded(recipient: SignalServiceAddress, isClosedGroup: Boolean) {
val publicKey = recipient.number
if (!isClosedGroup) { return }
delegate.sendSessionRequestIfNeeded(publicKey)
}
public fun shouldIgnoreMissingPreKeyBundleException(isClosedGroup: Boolean): Boolean {
// When a closed group is created, members try to establish sessions with eachother in the background through
// session requests. Until ALL users those session requests were sent to have come online, stored the pre key
// bundles contained in the session requests and replied with background messages to finalize the session
// creation, a given user won't be able to successfully send a message to all members of a group. This check
// is so that until we can do better on this front the user at least won't see this as an error in the UI.
return isClosedGroup
}
// endregion
}

View File

@ -1,6 +0,0 @@
package org.session.libsignal.service.loki.protocol.sessionmanagement
interface SessionManagementProtocolDelegate {
fun sendSessionRequestIfNeeded(publicKey: String)
}

View File

@ -1,4 +1,4 @@
package org.session.libsignal.service.loki.protocol.meta package org.session.libsignal.service.loki.utilities
public object TTLUtilities { public object TTLUtilities {

View File

@ -1,3 +1,3 @@
package org.session.libsignal.service.loki.protocol.mentions package org.session.libsignal.service.loki.utilities.mentions
data class Mention(val publicKey: String, val displayName: String) data class Mention(val publicKey: String, val displayName: String)

View File

@ -1,4 +1,4 @@
package org.session.libsignal.service.loki.protocol.mentions package org.session.libsignal.service.loki.utilities.mentions
import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol
import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol