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.LokiUserDatabase;
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.UiModeUtilities;
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.providers.BlobProvider;
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.IncomingMessageObserver;
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.LokiP2PAPIDelegate;
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol;
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager;
import java.io.File;
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 {
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 TypingStatusRepository typingStatusRepository;
@ -144,7 +140,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
private JobManager jobManager;
private ReadReceiptManager readReceiptManager;
private ProfileManager profileManager;
private IncomingMessageObserver incomingMessageObserver;
private ObjectGraph objectGraph;
private PersistentLogger persistentLogger;
@ -182,7 +177,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
SessionResetImplementation sessionResetImpl = new SessionResetImplementation(this);
MessagingConfiguration.Companion.configure(this,
DatabaseFactory.getStorage(this),
DatabaseFactory.getAttachmentProvider(this),
@ -191,7 +185,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
SwarmAPI.Companion.configureIfNeeded(apiDB);
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
MentionsManager.Companion.configureIfNeeded(userPublicKey, threadDB, userDB);
SessionMetaProtocol.Companion.configureIfNeeded(apiDB, userPublicKey);
}
setUpP2PAPIIfNeeded();
PushNotificationAPI.Companion.configureIfNeeded(BuildConfig.DEBUG);
@ -206,7 +199,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
UiModeUtilities.setupUiModeToUserSelected(this);
// ========
initializeJobManager();
initializeMessageRetrieval();
initializeExpiringMessageManager();
initializeTypingStatusRepository();
initializeTypingStatusSender();
@ -347,10 +339,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
.build());
}
public void initializeMessageRetrieval() {
this.incomingMessageObserver = new IncomingMessageObserver(this);
}
private void initializeDependencyInjection() {
communicationModule = new SignalCommunicationModule(this, new SignalServiceNetworkAccess(this));
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.util.guava.Optional;
import org.session.libsignal.service.loki.api.opengroups.PublicChat;
import org.session.libsignal.service.loki.protocol.mentions.Mention;
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import org.session.libsignal.service.loki.utilities.mentions.Mention;
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager;
import org.session.libsignal.service.loki.utilities.HexEncodingKt;
import org.session.libsignal.service.loki.utilities.PublicKeyValidation;
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.LokiUserDatabase;
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.MentionManagerUtilities;
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities;
@ -404,7 +402,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
});
sessionRestoreBannerView.setOnRestore(() -> {
SessionManagementProtocol.startSessionReset(this, recipient.getAddress().serialize());
updateSessionRestoreBanner();
return Unit.INSTANCE;
});
@ -2003,7 +2000,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
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";
updateSubtitleTextView();
updateMessageStatusProgressBar();
@ -2680,7 +2677,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
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);
if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) {
new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000);

View File

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

View File

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

View File

@ -32,7 +32,6 @@ import org.thoughtcrime.securesms.jobs.TypingSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.loki.api.SessionProtocolImpl;
import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
@ -88,20 +87,15 @@ public class SignalCommunicationModule {
@Provides
public synchronized SignalServiceMessageSender provideSignalMessageSender() {
if (this.messageSender == null) {
this.messageSender = new SignalServiceMessageSender(networkAccess.getConfiguration(context),
new DynamicCredentialsProvider(context),
this.messageSender = new SignalServiceMessageSender(new DynamicCredentialsProvider(context),
new SignalProtocolStoreImpl(context),
BuildConfig.USER_AGENT,
Optional.fromNullable(IncomingMessageObserver.getPipe()),
Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()),
Optional.of(new MessageSenderEventListener(context)),
TextSecurePreferences.getLocalNumber(context),
DatabaseFactory.getLokiAPIDatabase(context),
DatabaseFactory.getLokiThreadDatabase(context),
DatabaseFactory.getLokiMessageDatabase(context),
null, // DatabaseFactory.getLokiPreKeyBundleDatabase(context)
new SessionProtocolImpl(context),
new SessionResetImplementation(context),
DatabaseFactory.getLokiUserDatabase(context),
DatabaseFactory.getGroupDatabase(context),
((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.ResetThreadSessionJob;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupUpdateMessageSendJobV2;
import org.thoughtcrime.securesms.loki.protocol.NullMessageSendJob;
import java.util.ArrayList;
import java.util.Arrays;
@ -41,7 +40,6 @@ public final class JobManagerFactories {
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory());
put(MmsSendJob.KEY, new MmsSendJob.Factory());
put(NullMessageSendJob.KEY, new NullMessageSendJob.Factory());
put(PushContentReceiveJob.KEY, new PushContentReceiveJob.Factory());
put(PushDecryptJob.KEY, new PushDecryptJob.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.utilities.MediaTypes;
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.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.loki.api.crypto.SessionProtocol;
import org.session.libsignal.utilities.PromiseUtilities;
import org.thoughtcrime.securesms.ApplicationContext;
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.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
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.SyncMessageId;
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.protocol.ClosedGroupsProtocolV2;
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.SessionResetImplementation;
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
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.notifications.NotificationChannels;
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
import org.thoughtcrime.securesms.sms.IncomingEndSessionMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.session.libsignal.utilities.Hex;
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.util.guava.Optional;
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.shared.SharedContact;
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 java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
@ -242,10 +219,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
try {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context);
SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(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);
@ -254,8 +230,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return;
}
SessionManagementProtocol.handlePreKeyBundleMessageIfNeeded(context, content);
SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content);
if (content.configurationMessageProto.isPresent()) {
@ -341,7 +315,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
if (threadId != null) {
SessionManagementProtocol.handleEndSessionMessageIfNeeded(context, content);
messageNotifier.updateNotification(context, threadId);
}
}
@ -706,82 +679,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
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,
@ -905,42 +802,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
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) {
if (!sharedContacts.isPresent()) return Optional.absent();
@ -1069,10 +930,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return false;
}
private boolean isGroupChatMessage(SignalServiceContent content) {
return content.getDataMessage().isPresent() && content.getDataMessage().get().isGroupMessage();
}
private void resetRecipientToPush(@NonNull Recipient recipient) {
if (recipient.isForceSmsSelection()) {
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.SignalServiceDataMessage;
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.push.SignalServiceAddress;
import org.session.libsignal.service.api.push.exceptions.UnregisteredUserException;
import org.session.libsignal.service.loki.api.SnodeAPI;
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -285,7 +283,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
.asExpirationUpdate(message.isExpirationUpdate())
.build();
if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) {
if (userPublicKey == address.getNumber()) {
// Loki - Device link messages don't go through here
SendMessageResult result = messageSender.sendMessage(messageId, address, unidentifiedAccessPair, mediaMessage);
if (result.getLokiAPIError() != null) {

View File

@ -33,10 +33,7 @@ public abstract class PushReceivedJob extends BaseJob {
}
}
if (envelope.isReceipt()) {
handleReceipt(envelope);
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()
|| envelope.isUnidentifiedSender() || envelope.isFallbackMessage() || envelope.isClosedGroupCiphertext()) {
if (envelope.isUnidentifiedSender() || envelope.isClosedGroupCiphertext()) {
handleMessage(envelope, isPushNotification);
} else {
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);
}
@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) {
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.utilities.MediaTypes;
import org.session.libsignal.utilities.Base64;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util;
import org.greenrobot.eventbus.EventBus;
@ -34,13 +33,10 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
import org.session.libsignal.utilities.Hex;
import org.thoughtcrime.securesms.util.MediaUtil;
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.SignalServiceAttachmentPointer;
import org.session.libsignal.service.api.messages.SignalServiceDataMessage;
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.push.SignalServiceAddress;
@ -55,7 +51,6 @@ import java.util.concurrent.TimeUnit;
public abstract class PushSendJob extends SendJob {
private static final String TAG = PushSendJob.class.getSimpleName();
private static final long CERTIFICATE_EXPIRATION_BUFFER = TimeUnit.DAYS.toMillis(1);
protected PushSendJob(Job.Parameters parameters) {
super(parameters);
@ -72,14 +67,6 @@ public abstract class PushSendJob extends SendJob {
@Override
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();
}

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

View File

@ -87,16 +87,14 @@ public class TypingSendJob extends BaseJob implements InjectableType {
}
List<Recipient> recipients = Collections.singletonList(recipient);
Optional<byte[]> groupId = Optional.absent();
if (recipient.isGroupRecipient()) {
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<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);
}

View File

@ -193,8 +193,6 @@ class BackupRestoreViewModel(application: Application): AndroidViewModel(applica
application.setUpStorageAPIIfNeeded()
application.setUpP2PAPIIfNeeded()
HomeActivity.requestResetAllSessionsOnStartup(context)
BackupRestoreResult.SUCCESS
} catch (e: DatabaseDowngradeException) {
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.model.ThreadRecord
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.views.ConversationView
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.setBooleanPreference
import org.session.libsession.utilities.Util
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager
import org.session.libsignal.service.loki.protocol.meta.SessionMetaProtocol
import org.session.libsignal.service.loki.utilities.mentions.MentionsManager
import org.session.libsignal.utilities.ThreadUtils
import org.session.libsignal.service.loki.utilities.toHexString
import org.thoughtcrime.securesms.loki.dialogs.*
@ -54,31 +52,6 @@ import java.io.IOException
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 var broadcastReceiver: BroadcastReceiver? = null
@ -165,10 +138,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
val userDB = DatabaseFactory.getLokiUserDatabase(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val sessionResetImpl = SessionResetImplementation(this)
if (userPublicKey != null) {
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey)
application.publicChatManager.startPollersIfNeeded()
}
IP2Country.configureIfNeeded(this)

View File

@ -153,11 +153,23 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
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
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 processIncomingMessage(message: PublicChatMessage) {
if (isPollOngoing) { return Promise.of(Unit) }
isPollOngoing = true
val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize()
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
FileServerAPI.configure(userHexEncodedPublicKey, userPrivateKey, apiDB)
// Kovenant propagates a context to chained promises, so LokiPublicChatAPI.sharedContext should be used for all of the below
val promise = api.getMessages(group.channel, group.server).bind(PublicChatAPI.sharedContext) { messages ->
Promise.of(messages)
}
promise.successBackground { messages ->
// Process messages in the background
messages.forEach { message ->
// 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)
@ -181,57 +193,6 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
}
}
}
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) }
isPollOngoing = true
val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize()
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
FileServerAPI.configure(userHexEncodedPublicKey, userPrivateKey, apiDB)
// Kovenant propagates a context to chained promises, so LokiPublicChatAPI.sharedContext should be used for all of the below
val promise = api.getMessages(group.channel, group.server).bind(PublicChatAPI.sharedContext) { messages ->
Promise.of(messages)
}
promise.successBackground { messages ->
// Process messages in the background
messages.forEach { message ->
if (message.senderPublicKey == userHexEncodedPublicKey) {
processOutgoingMessage(message)
} else {
processIncomingMessage(message)
}
}
isCaughtUp = true
isPollOngoing = false
}

View File

@ -14,7 +14,6 @@ import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.TextSecurePreferences
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.service.loki.database.LokiThreadDatabaseProtocol
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)
}
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> {
val database = databaseHelper.readableDatabase
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.internal.push.SignalServiceProtos
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.toHexString
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.session.libsignal.utilities.Hex
import java.util.*
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) {

View File

@ -8,6 +8,7 @@ import org.session.libsession.utilities.TextSecurePreferences
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.internal.push.SignalServiceProtos.DataMessage
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.logging.Log
@ -72,8 +73,8 @@ object MultiDeviceProtocol {
for (closedGroup in configurationMessage.closedGroups) {
if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue
val closedGroupUpdate = SignalServiceProtos.ClosedGroupUpdateV2.newBuilder()
closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdateV2.Type.NEW
val closedGroupUpdate = DataMessage.ClosedGroupControlMessage.newBuilder()
closedGroupUpdate.type = DataMessage.ClosedGroupControlMessage.Type.NEW
closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey))
closedGroupUpdate.name = closedGroup.name
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.model.MessageRecord
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 {

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.mms.GlideRequests
import org.thoughtcrime.securesms.util.DateUtils
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.protocol.mentions.MentionsManager
import java.util.*
class ConversationView : LinearLayout {

View File

@ -10,7 +10,7 @@ import android.widget.ListView
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.utilities.toPx
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) {
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 org.thoughtcrime.securesms.mms.GlideRequests
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) {
var mentionCandidate = Mention("", "")

View File

@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.loki.utilities.AvatarPlaceholderGenerator
import org.thoughtcrime.securesms.mms.GlideRequests
import org.session.libsession.messaging.threads.recipients.Recipient
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?

View File

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

View File

@ -278,6 +278,12 @@ message GroupContext {
repeated string members = 4;
optional AttachmentPointer avatar = 5;
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 {

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

View File

@ -6,12 +6,10 @@
package org.session.libsignal.service.api;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.jetbrains.annotations.Nullable;
import org.session.libsignal.libsignal.ecc.ECKeyPair;
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.util.guava.Optional;
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.LokiThreadDatabaseProtocol;
import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol;
import org.session.libsignal.service.loki.protocol.meta.TTLUtilities;
import org.session.libsignal.service.loki.protocol.sessionmanagement.SessionManagementProtocol;
import org.session.libsignal.service.loki.utilities.TTLUtilities;
import org.session.libsignal.service.loki.utilities.Broadcaster;
import org.session.libsignal.service.loki.utilities.HexEncodingKt;
import org.session.libsignal.service.loki.utilities.PlaintextOutputStreamFactory;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import kotlin.Unit;
@ -100,10 +94,8 @@ public class SignalServiceMessageSender {
private static final String TAG = SignalServiceMessageSender.class.getSimpleName();
private final PushServiceSocket socket;
private final SignalProtocolStore store;
private final SignalServiceAddress localAddress;
private final Optional<EventListener> eventListener;
private final AtomicReference<Optional<SignalServiceMessagePipe>> pipe;
private final AtomicReference<Optional<SignalServiceMessagePipe>> unidentifiedPipe;
@ -113,9 +105,7 @@ public class SignalServiceMessageSender {
private final LokiAPIDatabaseProtocol apiDatabase;
private final LokiThreadDatabaseProtocol threadDatabase;
private final LokiMessageDatabaseProtocol messageDatabase;
private final LokiPreKeyBundleDatabaseProtocol preKeyBundleDatabase;
private final SessionProtocol sessionProtocolImpl;
private final SessionResetProtocol sessionResetImpl;
private final LokiUserDatabaseProtocol userDatabase;
private final LokiOpenGroupDatabaseProtocol openGroupDatabase;
private final Broadcaster broadcaster;
@ -123,65 +113,48 @@ public class SignalServiceMessageSender {
/**
* Construct a SignalServiceMessageSender.
*
* @param urls The URL of the Signal Service.
* @param user The Signal Service username (eg phone number).
* @param password The Signal Service user password.
* @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,
String user, String password,
public SignalServiceMessageSender(String user, String password,
SignalProtocolStore store,
String userAgent,
Optional<SignalServiceMessagePipe> pipe,
Optional<SignalServiceMessagePipe> unidentifiedPipe,
Optional<EventListener> eventListener,
String userPublicKey,
LokiAPIDatabaseProtocol apiDatabase,
LokiThreadDatabaseProtocol threadDatabase,
LokiMessageDatabaseProtocol messageDatabase,
LokiPreKeyBundleDatabaseProtocol preKeyBundleDatabase,
SessionProtocol sessionProtocolImpl,
SessionResetProtocol sessionResetImpl,
LokiUserDatabaseProtocol userDatabase,
LokiOpenGroupDatabaseProtocol openGroupDatabase,
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,
CredentialsProvider credentialsProvider,
public SignalServiceMessageSender(CredentialsProvider credentialsProvider,
SignalProtocolStore store,
String userAgent,
Optional<SignalServiceMessagePipe> pipe,
Optional<SignalServiceMessagePipe> unidentifiedPipe,
Optional<EventListener> eventListener,
String userPublicKey,
LokiAPIDatabaseProtocol apiDatabase,
LokiThreadDatabaseProtocol threadDatabase,
LokiMessageDatabaseProtocol messageDatabase,
LokiPreKeyBundleDatabaseProtocol preKeyBundleDatabase,
SessionProtocol sessionProtocolImpl,
SessionResetProtocol sessionResetImpl,
LokiUserDatabaseProtocol userDatabase,
LokiOpenGroupDatabaseProtocol openGroupDatabase,
Broadcaster broadcaster)
{
this.socket = new PushServiceSocket(urls, credentialsProvider, userAgent);
this.store = store;
this.localAddress = new SignalServiceAddress(credentialsProvider.getUser());
this.pipe = new AtomicReference<>(pipe);
this.unidentifiedPipe = new AtomicReference<>(unidentifiedPipe);
this.eventListener = eventListener;
this.userPublicKey = userPublicKey;
this.apiDatabase = apiDatabase;
this.threadDatabase = threadDatabase;
this.messageDatabase = messageDatabase;
this.preKeyBundleDatabase = preKeyBundleDatabase;
this.sessionProtocolImpl = sessionProtocolImpl;
this.sessionResetImpl = sessionResetImpl;
this.userDatabase = userDatabase;
this.openGroupDatabase = openGroupDatabase;
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.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.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.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.InvalidVersionException;
import org.session.libsignal.libsignal.LegacyMessageException;
import org.session.libsignal.libsignal.NoSessionException;
import org.session.libsignal.libsignal.SessionCipher;
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.util.guava.Optional;
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.database.LokiAPIDatabaseProtocol;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
@ -77,19 +56,16 @@ public class SignalServiceCipher {
private static final String TAG = SignalServiceCipher.class.getSimpleName();
private final SignalProtocolStore signalProtocolStore;
private final SessionResetProtocol sessionResetProtocol;
private final SignalServiceAddress localAddress;
private final SessionProtocol sessionProtocolImpl;
private final LokiAPIDatabaseProtocol apiDB;
public SignalServiceCipher(SignalServiceAddress localAddress,
SignalProtocolStore signalProtocolStore,
SessionResetProtocol sessionResetProtocol,
SessionProtocol sessionProtocolImpl,
LokiAPIDatabaseProtocol apiDB)
{
this.signalProtocolStore = signalProtocolStore;
this.sessionResetProtocol = sessionResetProtocol;
this.localAddress = localAddress;
this.sessionProtocolImpl = sessionProtocolImpl;
this.apiDB = apiDB;
@ -160,8 +136,8 @@ public class SignalServiceCipher {
protected Plaintext decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) throws InvalidMetadataMessageException
{
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSource(), envelope.getSourceDevice());
SessionCipher sessionCipher = new LokiSessionCipher(signalProtocolStore, sessionResetProtocol, sourceAddress);
SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, sessionResetProtocol, new SignalProtocolAddress(localAddress.getNumber(), 1));
SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);
SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, new SignalProtocolAddress(localAddress.getNumber(), 1));
byte[] paddedMessage;
Metadata metadata;

View File

@ -7,9 +7,7 @@
package org.session.libsignal.service.api.messages;
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.loki.protocol.sessionmanagement.PreKeyBundleMessage;
public class SignalServiceContent {
private final String sender;
@ -24,7 +22,6 @@ public class SignalServiceContent {
// Loki
public Optional<SignalServiceProtos.Content> configurationMessageProto = Optional.absent();
public Optional<PreKeyBundleMessage> preKeyBundleMessage = Optional.absent();
public Optional<String> senderDisplayName = 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.push.SignalServiceAddress;
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.List;

View File

@ -1,6 +1,6 @@
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 {

View File

@ -1,7 +1,7 @@
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;

View File

@ -1,7 +1,6 @@
package org.session.libsignal.service.api.messages;
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;
public class SignalServiceTypingMessage {

View File

@ -1,7 +1,7 @@
package org.session.libsignal.service.api.messages.calls;
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.List;

View File

@ -24483,6 +24483,70 @@ public final class SignalServiceProtos {
*/
com.google.protobuf.ByteString
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}
@ -24585,6 +24649,22 @@ public final class SignalServiceProtos {
admins_.add(input.readBytes());
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) {
@ -24599,6 +24679,12 @@ public final class SignalServiceProtos {
if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) {
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();
makeExtensionsImmutable();
}
@ -24913,6 +24999,90 @@ public final class SignalServiceProtos {
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() {
id_ = com.google.protobuf.ByteString.EMPTY;
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;
avatar_ = org.session.libsignal.service.internal.push.SignalServiceProtos.AttachmentPointer.getDefaultInstance();
admins_ = com.google.protobuf.LazyStringArrayList.EMPTY;
newMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
removedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@ -24951,6 +25123,12 @@ public final class SignalServiceProtos {
for (int i = 0; i < admins_.size(); 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);
}
@ -24994,6 +25172,24 @@ public final class SignalServiceProtos {
size += dataSize;
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();
memoizedSerializedSize = size;
return size;
@ -25127,6 +25323,10 @@ public final class SignalServiceProtos {
bitField0_ = (bitField0_ & ~0x00000010);
admins_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000020);
newMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000040);
removedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY;
bitField0_ = (bitField0_ & ~0x00000080);
return this;
}
@ -25187,6 +25387,18 @@ public final class SignalServiceProtos {
bitField0_ = (bitField0_ & ~0x00000020);
}
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_;
onBuilt();
return result;
@ -25237,6 +25449,26 @@ public final class SignalServiceProtos {
}
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());
return this;
}
@ -25745,6 +25977,246 @@ public final class SignalServiceProtos {
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)
}
@ -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" +
"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",
"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" +
"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 ." +
"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" +
"\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST_INFO\020" +
"\004\"\356\001\n\016ContactDetails\022\016\n\006number\030\001 \001(\t\022\014\n\004" +
"name\030\002 \001(\t\0224\n\006avatar\030\003 \001(\0132$.signalservi" +
"ce.ContactDetails.Avatar\022\r\n\005color\030\004 \001(\t\022",
"\022\n\nprofileKey\030\006 \001(\014\022\017\n\007blocked\030\007 \001(\010\022\023\n\013" +
"expireTimer\030\010 \001(\r\022\020\n\010nickname\030e \001(\t\032-\n\006A" +
"vatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006length\030\002 \001" +
"(\r\"\367\001\n\014GroupDetails\022\n\n\002id\030\001 \001(\014\022\014\n\004name\030" +
"\002 \001(\t\022\017\n\007members\030\003 \003(\t\0222\n\006avatar\030\004 \001(\0132\"" +
".signalservice.GroupDetails.Avatar\022\024\n\006ac" +
"tive\030\005 \001(\010:\004true\022\023\n\013expireTimer\030\006 \001(\r\022\r\n" +
"\005color\030\007 \001(\t\022\017\n\007blocked\030\010 \001(\010\022\016\n\006admins\030" +
"\t \003(\t\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006" +
"length\030\002 \001(\r\"\"\n\016PublicChatInfo\022\020\n\010server",
"ID\030\001 \001(\004BB\n+org.session.libsignal.servic" +
"e.internal.pushB\023SignalServiceProtos"
"s\030\006 \003(\t\022\023\n\nnewMembers\030\346\007 \003(\t\022\027\n\016removedM" +
"embers\030\347\007 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UP" +
"DATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST" +
"_INFO\020\004\"\356\001\n\016ContactDetails\022\016\n\006number\030\001 \001" +
"(\t\022\014\n\004name\030\002 \001(\t\0224\n\006avatar\030\003 \001(\0132$.signa",
"lservice.ContactDetails.Avatar\022\r\n\005color\030" +
"\004 \001(\t\022\022\n\nprofileKey\030\006 \001(\014\022\017\n\007blocked\030\007 \001" +
"(\010\022\023\n\013expireTimer\030\010 \001(\r\022\020\n\010nickname\030e \001(" +
"\t\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006leng" +
"th\030\002 \001(\r\"\367\001\n\014GroupDetails\022\n\n\002id\030\001 \001(\014\022\014\n" +
"\004name\030\002 \001(\t\022\017\n\007members\030\003 \003(\t\0222\n\006avatar\030\004" +
" \001(\0132\".signalservice.GroupDetails.Avatar" +
"\022\024\n\006active\030\005 \001(\010:\004true\022\023\n\013expireTimer\030\006 " +
"\001(\r\022\r\n\005color\030\007 \001(\t\022\017\n\007blocked\030\010 \001(\010\022\016\n\006a" +
"dmins\030\t \003(\t\032-\n\006Avatar\022\023\n\013contentType\030\001 \001",
"(\t\022\016\n\006length\030\002 \001(\r\"\"\n\016PublicChatInfo\022\020\n\010" +
"serverID\030\001 \001(\004BB\n+org.session.libsignal." +
"service.internal.pushB\023SignalServiceProt" +
"os"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -30651,7 +31125,7 @@ public final class SignalServiceProtos {
internal_static_signalservice_GroupContext_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
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 =
getDescriptor().getMessageTypes().get(10);
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.Base64
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.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 {

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)

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.LokiUserDatabaseProtocol