Merge remote-tracking branch 'upstream/dev' into open_groups_V2, working on compact poller implementation

# Conflicts:
#	app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java
#	app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java
#	app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/utilities/MentionManagerUtilities.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt
#	app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt
#	libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt
#	libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
#	libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt
#	libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt
#	libsession/src/main/java/org/session/libsession/messaging/messages/Destination.kt
#	libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPIV2.kt
#	libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupMessageV2.kt
#	libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupV2.kt
#	libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt
#	libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt
#	libsession/src/main/java/org/session/libsession/messaging/utilities/DotNetAPI.kt
#	libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt
#	libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt
#	libsession/src/main/java/org/session/libsession/snode/SnodeMessage.kt
#	libsession/src/main/java/org/session/libsession/utilities/mentions/MentionsManager.kt
#	libsignal/src/main/java/org/session/libsignal/service/loki/api/SwarmAPI.kt
#	libsignal/src/main/java/org/session/libsignal/service/loki/api/opengroups/PublicChat.kt
#	libsignal/src/main/java/org/session/libsignal/service/loki/utilities/mentions/MentionsManager.kt
This commit is contained in:
jubb 2021-04-28 17:41:30 +10:00
commit 51554f1cdf
158 changed files with 1112 additions and 16856 deletions

View File

@ -30,28 +30,25 @@ import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication;
import org.conscrypt.Conscrypt;
import org.session.libsession.messaging.MessagingConfiguration;
import org.session.libsession.messaging.MessagingModuleConfiguration;
import org.session.libsession.messaging.avatars.AvatarHelper;
import org.session.libsession.messaging.file_server.FileServerAPI;
import org.session.libsession.messaging.jobs.JobQueue;
import org.session.libsession.messaging.opengroups.OpenGroupAPI;
import org.session.libsession.messaging.mentions.MentionsManager;
import org.session.libsession.messaging.open_groups.OpenGroupAPI;
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier;
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPoller;
import org.session.libsession.messaging.sending_receiving.pollers.Poller;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.snode.SnodeConfiguration;
import org.session.libsession.snode.SnodeModule;
import org.session.libsession.utilities.IdentityKeyUtil;
import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper;
import org.session.libsession.utilities.dynamiclanguage.LocaleParser;
import org.session.libsession.utilities.mentions.MentionsManager;
import org.session.libsession.utilities.preferences.ProfileKeyUtil;
import org.session.libsignal.service.api.util.StreamDetails;
import org.session.libsignal.service.loki.api.PushNotificationAPI;
import org.session.libsignal.service.loki.api.SnodeAPI;
import org.session.libsignal.service.loki.api.SwarmAPI;
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI;
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol;
import org.session.libsignal.utilities.logging.Log;
import org.signal.aesgcmprovider.AesGcmProvider;
@ -96,6 +93,7 @@ import org.webrtc.voiceengine.WebRtcAudioUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
@ -173,17 +171,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
MessagingConfiguration.Companion.configure(this,
MessagingModuleConfiguration.Companion.configure(this,
DatabaseFactory.getStorage(this),
DatabaseFactory.getAttachmentProvider(this),
new SessionProtocolImpl(this));
SnodeConfiguration.Companion.configure(apiDB, broadcaster);
SnodeModule.Companion.configure(apiDB, broadcaster);
if (userPublicKey != null) {
SwarmAPI.Companion.configureIfNeeded(apiDB);
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
MentionsManager.Companion.configureIfNeeded(userPublicKey, threadDB, userDB);
MentionsManager.Companion.configureIfNeeded(userPublicKey, userDB);
}
PushNotificationAPI.Companion.configureIfNeeded(BuildConfig.DEBUG);
setUpStorageAPIIfNeeded();
resubmitProfilePictureIfNeeded();
publicChatManager = new PublicChatManager(this);
@ -428,7 +423,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabaseProtocol apiDB = DatabaseFactory.getLokiAPIDatabase(this);
FileServerAPI.Companion.configure(userPublicKey, userPrivateKey, apiDB);
org.session.libsession.messaging.fileserver.FileServerAPI.Companion.configure(userPublicKey, userPrivateKey, apiDB);
return true;
}
@ -458,13 +452,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
if (userPublicKey == null) return;
if (poller != null) {
SnodeAPI.shared.setUserPublicKey(userPublicKey);
poller.setUserPublicKey(userPublicKey);
return;
}
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
SwarmAPI.Companion.configureIfNeeded(apiDB);
SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
poller = new Poller();
closedGroupPoller = new ClosedGroupPoller();
}

View File

@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.threads.recipients.Recipient;

View File

@ -40,6 +40,7 @@ import androidx.loader.content.Loader;
import org.session.libsession.messaging.messages.visible.LinkPreview;
import org.session.libsession.messaging.messages.visible.Quote;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.session.libsession.messaging.open_groups.OpenGroup;
import org.session.libsession.messaging.sending_receiving.MessageSender;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus;
@ -64,7 +65,6 @@ import org.thoughtcrime.securesms.util.DateUtils;
import org.session.libsession.utilities.ExpirationUtil;
import org.session.libsession.utilities.Util;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.loki.api.opengroups.PublicChat;
import java.lang.ref.WeakReference;
import java.sql.Date;
@ -263,7 +263,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
}
toFrom.setText(toFromRes);
long threadID = messageRecord.getThreadId();
PublicChat openGroup = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadID);
OpenGroup openGroup = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadID);
if (openGroup != null && messageRecord.isOutgoing()) {
toFrom.setVisibility(View.GONE);
separator.setVisibility(View.GONE);

View File

@ -5,6 +5,7 @@ import android.text.TextUtils
import com.google.protobuf.ByteString
import org.greenrobot.eventbus.EventBus
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.utilities.DotNetAPI
@ -26,7 +27,6 @@ import org.thoughtcrime.securesms.util.MediaUtil
import java.io.IOException
import java.io.InputStream
class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), MessageDataProvider {
override fun getAttachmentStream(attachmentId: Long): SessionServiceAttachmentStream? {
@ -104,6 +104,10 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return smsDatabase.isOutgoingMessage(timestamp) || mmsDatabase.isOutgoingMessage(timestamp)
}
override fun getOpenGroup(threadID: Long): OpenGroup? {
return null // TODO: Implement
}
override fun updateAttachmentAfterUploadSucceeded(attachmentId: Long, attachmentStream: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: DotNetAPI.UploadResult) {
val database = DatabaseFactory.getAttachmentDatabase(context)
val databaseAttachment = getDatabaseAttachment(attachmentId) ?: return

View File

@ -30,7 +30,7 @@ import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.utilities.TextSecurePreferences;

View File

@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import network.loki.messenger.R;
import okhttp3.HttpUrl;

View File

@ -21,6 +21,7 @@ import androidx.annotation.RequiresApi;
import com.annimon.stream.Stream;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.session.libsession.messaging.open_groups.OpenGroup;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@ -35,7 +36,6 @@ import org.session.libsession.messaging.threads.recipients.RecipientModifiedList
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.ThemeUtil;
import org.session.libsession.utilities.Util;
import org.session.libsignal.service.loki.api.opengroups.PublicChat;
import java.util.List;
@ -201,7 +201,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
long threadID = DatabaseFactory.getThreadDatabase(getContext()).getOrCreateThreadIdFor(conversationRecipient);
String senderHexEncodedPublicKey = author.getAddress().serialize();
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadID);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadID);
if (senderHexEncodedPublicKey.equalsIgnoreCase(TextSecurePreferences.getLocalNumber(getContext()))) {
quoteeDisplayName = TextSecurePreferences.getProfileName(getContext());
} else if (publicChat != null) {

View File

@ -83,15 +83,16 @@ import com.annimon.stream.Stream;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.session.libsession.messaging.mentions.MentionsManager;
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate;
import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage;
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
import org.session.libsession.messaging.messages.signal.OutgoingSecureMediaMessage;
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.session.libsession.messaging.open_groups.OpenGroup;
import org.session.libsession.messaging.sending_receiving.MessageSender;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.threads.Address;
@ -109,11 +110,9 @@ import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.ViewUtil;
import org.session.libsession.utilities.concurrent.AssertedSuccessListener;
import org.session.libsession.utilities.mentions.Mention;
import org.session.libsession.utilities.mentions.MentionsManager;
import org.session.libsession.utilities.views.Stub;
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.utilities.HexEncodingKt;
import org.session.libsignal.service.loki.utilities.PublicKeyValidation;
import org.session.libsignal.utilities.concurrent.ListenableFuture;
@ -177,8 +176,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.MmsException;
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
import org.session.libsession.messaging.messages.signal.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.QuoteId;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
@ -188,8 +185,6 @@ import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.search.model.MessageResult;
import org.session.libsession.messaging.sending_receiving.MessageSender;
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DateUtils;
@ -378,7 +373,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(threadId, this);
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
if (publicChat != null) {
// Request open group info update and handle the successful result in #onOpenGroupInfoUpdated().
PublicChatInfoUpdateWorker.scheduleInstant(this, publicChat.getServer(), publicChat.getChannel());
@ -1401,7 +1396,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Subscribe(threadMode = ThreadMode.MAIN)
public void onOpenGroupInfoUpdated(OpenGroupUtilities.GroupInfoUpdatedEvent event) {
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
if (publicChat != null &&
publicChat.getChannel() == event.getChannel() &&
publicChat.getServer().equals(event.getUrl())) {
@ -2339,7 +2334,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
muteIndicatorImageView.setVisibility(View.VISIBLE);
subtitleTextView.setText("Muted until " + DateUtils.getFormattedDateTime(recipient.mutedUntil, "EEE, MMM d, yyyy HH:mm", Locale.getDefault()));
} else if (recipient.isGroupRecipient() && recipient.getName() != null && !recipient.getName().equals("Session Updates") && !recipient.getName().equals("Loki News")) {
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
if (publicChat != null) {
Integer userCount = DatabaseFactory.getLokiAPIDatabase(this).getUserCount(publicChat.getChannel(), publicChat.getServer());
if (userCount == null) { userCount = 0; }

View File

@ -57,17 +57,18 @@ import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
import com.annimon.stream.Stream;
import org.session.libsession.messaging.messages.control.DataExtractionNotification;
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
import org.session.libsession.messaging.messages.control.DataExtractionNotification;
import org.session.libsession.messaging.messages.visible.Quote;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.session.libsession.messaging.opengroups.OpenGroupAPI;
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2;
import org.session.libsession.messaging.opengroups.OpenGroupV2;
import org.session.libsession.messaging.open_groups.OpenGroup;
import org.session.libsession.messaging.open_groups.OpenGroupAPI;
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2;
import org.session.libsession.messaging.open_groups.OpenGroupV2;
import org.session.libsession.messaging.sending_receiving.MessageSender;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.utilities.TextSecurePreferences;
@ -76,7 +77,6 @@ import org.session.libsession.utilities.ViewUtil;
import org.session.libsession.utilities.concurrent.SimpleTask;
import org.session.libsession.utilities.task.ProgressDialogAsyncTask;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.loki.api.opengroups.PublicChat;
import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.MessageDetailsActivity;
@ -397,7 +397,7 @@ public class ConversationFragment extends Fragment
boolean isGroupChat = recipient.isGroupRecipient();
if (isGroupChat) {
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
boolean isPublicChat = (publicChat != null || openGroupChat != null);
int selectedMessageCount = messageRecords.size();
@ -514,7 +514,7 @@ public class ConversationFragment extends Fragment
builder.setMessage(getActivity().getResources().getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messagesCount, messagesCount));
builder.setCancelable(true);
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
@ -620,7 +620,7 @@ public class ConversationFragment extends Fragment
builder.setTitle(R.string.ConversationFragment_ban_selected_user);
builder.setCancelable(true);
final PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
final OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId);
final OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
builder.setPositiveButton(R.string.ban, (dialog, which) -> {

View File

@ -54,10 +54,11 @@ import com.annimon.stream.Stream;
import org.session.libsession.messaging.jobs.AttachmentDownloadJob;
import org.session.libsession.messaging.jobs.JobQueue;
import org.session.libsession.messaging.opengroups.OpenGroupAPI;
import org.session.libsession.messaging.open_groups.OpenGroup;
import org.session.libsession.messaging.open_groups.OpenGroupAPI;
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress;
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.messaging.threads.recipients.RecipientModifiedListener;
import org.session.libsession.utilities.GroupUtil;
@ -67,7 +68,6 @@ import org.session.libsession.utilities.Util;
import org.session.libsession.utilities.ViewUtil;
import org.session.libsession.utilities.views.Stub;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.loki.api.opengroups.PublicChat;
import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.BindableConversationItem;
import org.thoughtcrime.securesms.MediaPreviewActivity;
@ -724,7 +724,7 @@ public class ConversationItem extends LinearLayout
String publicKey = recipient.getAddress().toString();
profilePictureView.setPublicKey(publicKey);
String displayName = recipient.getName();
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID);
if (displayName == null && publicChat != null) {
displayName = DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.getId(), publicKey);
}
@ -911,7 +911,7 @@ public class ConversationItem extends LinearLayout
profilePictureView.setVisibility(VISIBLE);
int visibility = View.GONE;
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(messageRecord.getThreadId());
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(messageRecord.getThreadId());
if (publicChat != null) {
boolean isModerator = OpenGroupAPI.isUserModerator(current.getRecipient().getAddress().toString(), publicChat.getChannel(), publicChat.getServer());
visibility = isModerator ? View.VISIBLE : View.GONE;

View File

@ -14,7 +14,7 @@ import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.session.libsession.messaging.sending_receiving.dataextraction.DataExtractionNotificationInfoMessage;
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage;
import org.thoughtcrime.securesms.BindableConversationItem;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;

View File

@ -28,7 +28,6 @@ import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd;
import com.google.android.mms.pdu_alt.PduHeaders;
import com.google.protobuf.ByteString;
import net.sqlcipher.database.SQLiteDatabase;
@ -60,7 +59,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId;
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.threads.recipients.Recipient;

View File

@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.database
import android.content.Context
import android.net.Uri
import com.google.protobuf.ByteString
import org.session.libsession.messaging.StorageProtocol
import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.Job
@ -13,19 +12,18 @@ import org.session.libsession.messaging.messages.signal.*
import org.session.libsession.messaging.messages.signal.IncomingTextMessage
import org.session.libsession.messaging.messages.visible.Attachment
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.opengroups.OpenGroup
import org.session.libsession.messaging.opengroups.OpenGroupV2
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.dataextraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.Address.Companion.fromSerialized
import org.session.libsession.messaging.threads.GroupRecord
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.messaging.utilities.UpdateMessageBuilder
import org.session.libsession.messaging.utilities.UpdateMessageData
import org.session.libsession.messaging.utilities.ClosedGroupUpdateMessageData
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.IdentityKeyUtil
import org.session.libsession.utilities.TextSecurePreferences
@ -35,7 +33,6 @@ import org.session.libsignal.libsignal.util.KeyHelper
import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
import org.session.libsignal.service.api.messages.SignalServiceGroup
import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
@ -45,7 +42,6 @@ import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
import org.thoughtcrime.securesms.loki.utilities.get
import org.thoughtcrime.securesms.loki.utilities.getString
import org.thoughtcrime.securesms.mms.PartAuthority
import java.util.*
class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol {
override fun getUserPublicKey(): String? {
@ -469,7 +465,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>, sentTimestamp: Long) {
val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true)
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
val updateData = ClosedGroupUpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON()
val infoMessage = IncomingGroupMessage(m, groupID, updateData, true)
val smsDB = DatabaseFactory.getSmsDatabase(context)
smsDB.insertMessageInbox(infoMessage)
@ -479,7 +475,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val userPublicKey = getUserPublicKey()
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
val updateData = ClosedGroupUpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, true, null, listOf(), listOf())
val mmsDB = DatabaseFactory.getMmsDatabase(context)
val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context)

View File

@ -23,7 +23,7 @@ import android.text.SpannableString;
import network.loki.messenger.R;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
import org.session.libsession.database.documents.IdentityKeyMismatch;

View File

@ -25,9 +25,9 @@ import android.text.style.StyleSpan;
import network.loki.messenger.R;
import org.session.libsession.messaging.sending_receiving.dataextraction.DataExtractionNotificationInfoMessage;
import org.session.libsession.messaging.utilities.UpdateMessageBuilder;
import org.session.libsession.messaging.utilities.UpdateMessageData;
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage;
import org.session.libsession.messaging.utilities.ClosedGroupUpdateMessageBuilder;
import org.session.libsession.messaging.utilities.ClosedGroupUpdateMessageData;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.session.libsession.database.documents.IdentityKeyMismatch;
@ -93,14 +93,14 @@ public abstract class MessageRecord extends DisplayRecord {
@Override
public SpannableString getDisplayBody(@NonNull Context context) {
if(isGroupUpdateMessage()) {
UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(getBody());
return new SpannableString(UpdateMessageBuilder.INSTANCE.buildGroupUpdateMessage(context, updateMessageData, getIndividualRecipient().getAddress().serialize(), isOutgoing()));
ClosedGroupUpdateMessageData updateMessageData = ClosedGroupUpdateMessageData.Companion.fromJSON(getBody());
return new SpannableString(ClosedGroupUpdateMessageBuilder.INSTANCE.buildGroupUpdateMessage(context, updateMessageData, getIndividualRecipient().getAddress().serialize(), isOutgoing()));
} else if (isExpirationTimerUpdate()) {
int seconds = (int) (getExpiresIn() / 1000);
return new SpannableString(UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, seconds, getIndividualRecipient().getAddress().serialize(), isOutgoing()));
return new SpannableString(ClosedGroupUpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, seconds, getIndividualRecipient().getAddress().serialize(), isOutgoing()));
} else if (isDataExtraction()) {
if (isScreenshotExtraction()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize())));
else if (isMediaSavedExtraction()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize())));
if (isScreenshotExtraction()) return new SpannableString((ClosedGroupUpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize())));
else if (isMediaSavedExtraction()) return new SpannableString((ClosedGroupUpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize())));
}
// TODO below lines are left here for compatibility with older group update messages, it can be deleted later on
else if (isGroupUpdate() && isOutgoing()) {

View File

@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.database.documents.IdentityKeyMismatch;

View File

@ -28,8 +28,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.messaging.utilities.UpdateMessageBuilder;
import org.session.libsession.messaging.utilities.UpdateMessageData;
import org.session.libsession.utilities.ExpirationUtil;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.SmsDatabase;

View File

@ -4,6 +4,8 @@ import android.graphics.Bitmap;
import androidx.annotation.NonNull;
import org.session.libsession.messaging.jobs.Data;
import org.session.libsession.utilities.DownloadUtilities;
import org.session.libsignal.service.api.crypto.AttachmentCipherInputStream;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.session.libsession.messaging.threads.GroupRecord;
@ -22,6 +24,7 @@ import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
import org.session.libsignal.service.api.push.exceptions.NonSuccessfulResponseCodeException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@ -91,9 +94,20 @@ public class AvatarDownloadJob extends BaseJob implements InjectableType {
attachment = File.createTempFile("avatar", "tmp", context.getCacheDir());
attachment.deleteOnExit();
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url);
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE);
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url);
if (pointer.getUrl().isEmpty()) throw new InvalidMessageException("Missing attachment URL.");
DownloadUtilities.downloadFile(attachment, pointer.getUrl(), MAX_AVATAR_SIZE, null);
// Assume we're retrieving an attachment for an open group server if the digest is not set
InputStream inputStream;
if (!pointer.getDigest().isPresent()) {
inputStream = new FileInputStream(attachment);
} else {
inputStream = AttachmentCipherInputStream.createForAttachment(attachment, pointer.getSize().or(0), pointer.getKey(), pointer.getDigest().get());
}
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
database.updateProfilePicture(groupId, avatar);
inputStream.close();

View File

@ -10,9 +10,11 @@ import org.session.libsession.messaging.avatars.AvatarHelper;
import org.session.libsession.messaging.jobs.Data;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.utilities.DownloadUtilities;
import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.Util;
import org.session.libsignal.service.api.SignalServiceMessageReceiver;
import org.session.libsignal.service.api.crypto.ProfileCipherInputStream;
import org.session.libsignal.service.api.push.exceptions.PushNetworkException;
import org.session.libsignal.utilities.logging.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@ -22,6 +24,7 @@ import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -102,7 +105,8 @@ public class RetrieveProfileAvatarJob extends BaseJob implements InjectableType
File downloadDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
try {
InputStream avatarStream = receiver.retrieveProfileAvatar(profileAvatar, downloadDestination, profileKey, MAX_PROFILE_SIZE_BYTES);
DownloadUtilities.downloadFile(downloadDestination, profileAvatar, MAX_PROFILE_SIZE_BYTES, null);
InputStream avatarStream = new ProfileCipherInputStream(new FileInputStream(downloadDestination), profileKey);
File decryptDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
Util.copy(avatarStream, new FileOutputStream(decryptDestination));

View File

@ -25,7 +25,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil.OpenGraph;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.attachments.UriAttachment;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.utilities.concurrent.SignalExecutors;
import java.io.ByteArrayOutputStream;

View File

@ -13,9 +13,8 @@ import org.session.libsession.utilities.Debouncer;
import org.session.libsession.utilities.Util;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import java.util.Collections;
import java.util.List;

View File

@ -30,10 +30,10 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.opengroups.OpenGroupAPI
import org.session.libsession.messaging.mentions.MentionsManager
import org.session.libsession.messaging.open_groups.OpenGroupAPI
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.utilities.*
import org.session.libsession.utilities.mentions.MentionsManager
import org.session.libsignal.service.loki.utilities.toHexString
import org.session.libsignal.utilities.ThreadUtils
import org.thoughtcrime.securesms.ApplicationContext
@ -139,7 +139,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
val userDB = DatabaseFactory.getLokiUserDatabase(this)
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
if (userPublicKey != null) {
MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB)
MentionsManager.configureIfNeeded(userPublicKey, userDB)
application.publicChatManager.startPollersIfNeeded()
JobQueue.shared.resumePendingJobs()
}

View File

@ -24,7 +24,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import network.loki.messenger.R
import okhttp3.HttpUrl
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2.DefaultGroup
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2.DefaultGroup
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.DistributionTypes
import org.session.libsession.messaging.threads.recipients.Recipient

View File

@ -19,12 +19,12 @@ import android.widget.Toast
import androidx.annotation.ColorRes
import kotlinx.android.synthetic.main.activity_path.*
import network.loki.messenger.R
import org.session.libsession.snode.OnionRequestAPI
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.loki.utilities.*
import org.thoughtcrime.securesms.loki.views.GlowViewUtilities
import org.thoughtcrime.securesms.loki.views.PathDotView
import org.session.libsignal.service.loki.api.Snode
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
import org.session.libsignal.service.loki.Snode
class PathActivity : PassphraseRequiredActionBarActivity() {
private val broadcastReceivers = mutableListOf<BroadcastReceiver>()

View File

@ -28,13 +28,13 @@ import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.task
import nl.komponents.kovenant.ui.alwaysUi
import org.session.libsession.messaging.avatars.AvatarHelper
import org.session.libsession.messaging.opengroups.OpenGroupAPI
import org.session.libsession.messaging.file_server.FileServerAPI
import org.session.libsession.messaging.open_groups.OpenGroupAPI
import org.session.libsession.messaging.threads.Address
import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.preferences.ProfileKeyUtil
import org.session.libsignal.service.api.util.StreamDetails
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.avatar.AvatarSelection

View File

@ -8,13 +8,14 @@ import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.all
import nl.komponents.kovenant.functional.map
import org.session.libsession.messaging.jobs.MessageReceiveJob
import org.session.libsession.messaging.opengroups.OpenGroup
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPoller
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.api.SnodeAPI
import org.session.libsignal.utilities.logging.Log
import org.thoughtcrime.securesms.database.DatabaseFactory
import java.io.IOException
import java.util.concurrent.TimeUnit
class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Worker(context, params) {
@ -70,7 +71,7 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
// Private chats
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
val privateChatsPromise = SnodeAPI.shared.getMessages(userPublicKey).map { envelopes ->
val privateChatsPromise = SnodeAPI.getMessages(userPublicKey).map { envelopes ->
envelopes.map { envelope ->
MessageReceiveJob(envelope.toByteArray(), false).executeAsync()
}

View File

@ -3,12 +3,12 @@ package org.thoughtcrime.securesms.loki.api
import android.content.Context
import nl.komponents.kovenant.functional.map
import okhttp3.*
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
import org.session.libsession.snode.OnionRequestAPI
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.utilities.JsonUtil
import org.session.libsignal.service.loki.api.PushNotificationAPI
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
import org.session.libsignal.service.loki.utilities.retryIfNeeded
object LokiPushNotificationManager {
@ -16,10 +16,10 @@ object LokiPushNotificationManager {
private val tokenExpirationInterval = 12 * 60 * 60 * 1000
private val server by lazy {
PushNotificationAPI.shared.server
PushNotificationAPI.server
}
private val pnServerPublicKey by lazy {
PushNotificationAPI.pnServerPublicKey
PushNotificationAPI.serverPublicKey
}
enum class ClosedGroupOperation {

View File

@ -2,9 +2,9 @@ package org.thoughtcrime.securesms.loki.api
import android.content.Context
import androidx.work.*
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsignal.utilities.logging.Log
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
import org.session.libsignal.service.loki.api.opengroups.PublicChat
/**
* Delegates the [OpenGroupUtilities.updateGroupInfo] call to the work manager.
@ -40,7 +40,7 @@ class PublicChatInfoUpdateWorker(val context: Context, params: WorkerParameters)
val serverUrl = inputData.getString(DATA_KEY_SERVER_URL)!!
val channel = inputData.getLong(DATA_KEY_CHANNEL, -1)
val publicChatId = PublicChat.getId(channel, serverUrl)
val publicChatId = OpenGroup.getId(channel, serverUrl)
return try {
Log.v(TAG, "Updating open group info for $publicChatId.")

View File

@ -5,13 +5,12 @@ import android.database.ContentObserver
import android.graphics.Bitmap
import android.text.TextUtils
import androidx.annotation.WorkerThread
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.opengroups.*
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.*
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupV2Poller
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.Util
import org.session.libsignal.service.loki.api.opengroups.PublicChat
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.groups.GroupManager
@ -82,7 +81,7 @@ class PublicChatManager(private val context: Context) {
@WorkerThread
public fun addChat(server: String, channel: Long, info: OpenGroupInfo): OpenGroup {
val chat = PublicChat(channel, server, info.displayName, true)
val chat = OpenGroup(channel, server, info.displayName, true)
var threadID = GroupManager.getOpenGroupThreadID(chat.id, context)
var profilePicture: Bitmap? = null
// Create the group if we don't have one
@ -103,7 +102,7 @@ class PublicChatManager(private val context: Context) {
// Start polling
Util.runOnMain { startPollersIfNeeded() }
return OpenGroup.from(chat)
return chat
}
@WorkerThread
@ -128,7 +127,7 @@ class PublicChatManager(private val context: Context) {
public fun removeChat(server: String, channel: Long) {
val threadDB = DatabaseFactory.getThreadDatabase(context)
val groupId = PublicChat.getId(channel, server)
val groupId = OpenGroup.getId(channel, server)
val threadId = GroupManager.getOpenGroupThreadID(groupId, context)
val groupAddress = threadDB.getRecipientForThreadId(threadId)!!.address.serialize()
GroupManager.deleteGroup(groupAddress, context)
@ -147,7 +146,7 @@ class PublicChatManager(private val context: Context) {
}
private fun refreshChatsAndPollers() {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val chatsInDB = storage.getAllOpenGroups()
val v2ChatsInDB = storage.getAllV2OpenGroups()
val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) }

View File

@ -6,8 +6,8 @@ import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageReceiveJob
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.service.loki.api.MessageWrapper
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.logging.Log
import org.thoughtcrime.securesms.notifications.NotificationChannels

View File

@ -7,7 +7,7 @@ import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.libsignal.ecc.DjbECPrivateKey
import org.session.libsignal.libsignal.ecc.DjbECPublicKey
import org.session.libsignal.libsignal.ecc.ECKeyPair
import org.session.libsignal.service.loki.api.Snode
import org.session.libsignal.service.loki.Snode
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol
import org.session.libsignal.service.loki.utilities.PublicKeyValidation
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
@ -353,7 +353,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
fun removeLastDeletionServerID(room: String, server: String) {
val database = databaseHelper.writableDatabase
val index = "$server.$room"
database.delete(lastDeletionServerIDTable, "$lastDeletionServerID = ?", wrap(index))
database.delete(lastDeletionServerIDTable, "$lastDeletionServerIDTableIndex = ?", wrap(index))
}
fun removeLastDeletionServerID(group: Long, server: String) {

View File

@ -3,21 +3,20 @@ package org.thoughtcrime.securesms.loki.database
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import org.session.libsession.messaging.opengroups.OpenGroupV2
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsignal.service.loki.api.opengroups.PublicChat
import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol
import org.session.libsignal.utilities.JsonUtil
import org.session.libsession.messaging.open_groups.OpenGroup
import org.thoughtcrime.securesms.database.Database
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.loki.utilities.get
import org.thoughtcrime.securesms.loki.utilities.getLong
import org.thoughtcrime.securesms.loki.utilities.getString
import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate
import org.thoughtcrime.securesms.loki.utilities.*
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol {
import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsignal.utilities.JsonUtil
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
companion object {
private val sessionResetTable = "loki_thread_session_reset_database"
@ -32,22 +31,22 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
val createPublicChatTableCommand = "CREATE TABLE $publicChatTable ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);"
}
override fun getThreadID(hexEncodedPublicKey: String): Long {
fun getThreadID(hexEncodedPublicKey: String): Long {
val address = Address.fromSerialized(hexEncodedPublicKey)
val recipient = Recipient.from(context, address, false)
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
}
fun getAllPublicChats(): Map<Long, PublicChat> {
fun getAllPublicChats(): Map<Long, OpenGroup> {
val database = databaseHelper.readableDatabase
var cursor: Cursor? = null
val result = mutableMapOf<Long, PublicChat>()
val result = mutableMapOf<Long, OpenGroup>()
try {
cursor = database.rawQuery("select * from $publicChatTable", null)
while (cursor != null && cursor.moveToNext()) {
val threadID = cursor.getLong(threadID)
val string = cursor.getString(publicChat)
val publicChat = PublicChat.fromJSON(string)
val publicChat = OpenGroup.fromJSON(string)
if (publicChat != null) {
result[threadID] = publicChat
}
@ -84,6 +83,16 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
return getAllPublicChats().values.fold(setOf()) { set, chat -> set.plus(chat.server) }
}
fun getPublicChat(threadID: Long): OpenGroup? {
if (threadID < 0) { return null }
val database = databaseHelper.readableDatabase
return database.get(publicChatTable, "${Companion.threadID} = ?", arrayOf(threadID.toString())) { cursor ->
val publicChatAsJSON = cursor.getString(publicChat)
OpenGroup.fromJSON(publicChatAsJSON)
}
}
fun getOpenGroupChat(threadID: Long): OpenGroupV2? {
if (threadID < 0) {
return null
@ -106,18 +115,7 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
database.insertOrUpdate(publicChatTable, contentValues, "${Companion.threadID} = ?", arrayOf(threadID.toString()))
}
override fun getPublicChat(threadID: Long): PublicChat? {
if (threadID < 0) {
return null
}
val database = databaseHelper.readableDatabase
return database.get(publicChatTable, "${Companion.threadID} = ?", arrayOf(threadID.toString())) { cursor ->
val publicChatAsJSON = cursor.getString(publicChat)
PublicChat.fromJSON(publicChatAsJSON)
}
}
override fun setPublicChat(publicChat: PublicChat, threadID: Long) {
fun setPublicChat(publicChat: OpenGroup, threadID: Long) {
if (threadID < 0) {
return
}
@ -128,7 +126,7 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
database.insertOrUpdate(publicChatTable, contentValues, "${Companion.threadID} = ?", arrayOf(threadID.toString()))
}
override fun removePublicChat(threadID: Long) {
fun removePublicChat(threadID: Long) {
databaseHelper.writableDatabase.delete(publicChatTable, "${Companion.threadID} = ?", arrayOf(threadID.toString()))
}
}

View File

@ -31,6 +31,7 @@ import org.session.libsession.utilities.TextSecurePreferences
import java.util.*
object ClosedGroupsProtocolV2 {
@JvmStatic
fun handleMessage(context: Context, closedGroupUpdate: DataMessage.ClosedGroupControlMessage, sentTimestamp: Long, groupPublicKey: String, senderPublicKey: String) {
if (!isValid(context, closedGroupUpdate, senderPublicKey, sentTimestamp)) { return }
@ -40,7 +41,6 @@ object ClosedGroupsProtocolV2 {
DataMessage.ClosedGroupControlMessage.Type.MEMBERS_ADDED -> handleClosedGroupMembersAdded(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
DataMessage.ClosedGroupControlMessage.Type.NAME_CHANGE -> handleClosedGroupNameChange(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT -> handleClosedGroupMemberLeft(context, sentTimestamp, groupPublicKey, senderPublicKey)
DataMessage.ClosedGroupControlMessage.Type.UPDATE -> handleClosedGroupUpdate(context, closedGroupUpdate, sentTimestamp, groupPublicKey, senderPublicKey)
DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR -> handleGroupEncryptionKeyPair(context, closedGroupUpdate, groupPublicKey, senderPublicKey)
else -> {
Log.d("Loki","Can't handle closed group update of unknown type: ${closedGroupUpdate.type}")
@ -64,7 +64,6 @@ object ClosedGroupsProtocolV2 {
DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT -> {
senderPublicKey.isNotEmpty()
}
DataMessage.ClosedGroupControlMessage.Type.UPDATE,
DataMessage.ClosedGroupControlMessage.Type.NAME_CHANGE -> {
!closedGroupUpdate.name.isNullOrEmpty()
}

View File

@ -7,7 +7,7 @@ import android.content.IntentFilter
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import org.session.libsignal.utilities.logging.Log
import com.opencsv.CSVReader
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
import org.session.libsession.snode.OnionRequestAPI
import org.session.libsignal.utilities.ThreadUtils
import java.io.File
import java.io.FileOutputStream

View File

@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.loki.utilities
import android.content.Context
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.mentions.MentionsManager
import org.session.libsession.messaging.mentions.MentionsManager
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.model.MessageRecord

View File

@ -3,15 +3,14 @@ package org.thoughtcrime.securesms.loki.utilities
import android.content.Context
import androidx.annotation.WorkerThread
import org.greenrobot.eventbus.EventBus
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.opengroups.OpenGroup
import org.session.libsession.messaging.opengroups.OpenGroupAPI
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2
import org.session.libsession.messaging.opengroups.OpenGroupV2
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.open_groups.OpenGroupAPI
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.preferences.ProfileKeyUtil
import org.session.libsignal.service.loki.api.opengroups.PublicChat
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.groups.GroupManager
@ -29,14 +28,14 @@ object OpenGroupUtilities {
val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getOpenGroupChat(threadID)
if (openGroup != null) return openGroup
MessagingConfiguration.shared.storage.setOpenGroupPublicKey(server,publicKey)
MessagingModuleConfiguration.shared.storage.setOpenGroupPublicKey(server,publicKey)
OpenGroupAPIV2.getAuthToken(room, server).get()
val groupInfo = OpenGroupAPIV2.getInfo(room,server).get()
val application = ApplicationContext.getInstance(context)
val group = application.publicChatManager.addChat(server, room, groupInfo, publicKey)
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
storage.removeLastDeletionServerId(room, server)
storage.removeLastMessageServerId(room, server)
@ -48,10 +47,10 @@ object OpenGroupUtilities {
@Throws(Exception::class)
fun addGroup(context: Context, url: String, channel: Long): OpenGroup {
// Check for an existing group.
val groupID = PublicChat.getId(channel, url)
val groupID = OpenGroup.getId(channel, url)
val threadID = GroupManager.getOpenGroupThreadID(groupID, context)
val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
if (openGroup != null) { return OpenGroup.from(openGroup) }
if (openGroup != null) { return openGroup }
// Add the new group.
val application = ApplicationContext.getInstance(context)
@ -81,7 +80,7 @@ object OpenGroupUtilities {
@Throws(Exception::class)
fun updateGroupInfo(context: Context, url: String, channel: Long) {
// Check if open group has a related DB record.
val groupId = GroupUtil.getEncodedOpenGroupID(PublicChat.getId(channel, url).toByteArray())
val groupId = GroupUtil.getEncodedOpenGroupID(OpenGroup.getId(channel, url).toByteArray())
if (!DatabaseFactory.getGroupDatabase(context).hasGroup(groupId)) {
throw IllegalStateException("Attempt to update open group info for non-existent DB record: $groupId")
}

View File

@ -4,7 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
typealias DefaultGroups = List<OpenGroupAPIV2.DefaultGroup>
typealias GroupState = State<DefaultGroups>

View File

@ -8,7 +8,7 @@ import android.view.ViewGroup
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.view_mention_candidate.view.*
import network.loki.messenger.R
import org.session.libsession.messaging.opengroups.OpenGroupAPI
import org.session.libsession.messaging.open_groups.OpenGroupAPI
import org.session.libsession.utilities.mentions.Mention
import org.thoughtcrime.securesms.mms.GlideRequests

View File

@ -11,9 +11,9 @@ import android.util.AttributeSet
import android.view.View
import androidx.annotation.ColorInt
import network.loki.messenger.R
import org.session.libsession.snode.OnionRequestAPI
import org.thoughtcrime.securesms.loki.utilities.getColorWithID
import org.thoughtcrime.securesms.loki.utilities.toPx
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
class PathStatusView : View {
private val broadcastReceivers = mutableListOf<BroadcastReceiver>()

View File

@ -11,10 +11,10 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import kotlinx.android.synthetic.main.view_profile_picture.view.*
import network.loki.messenger.R
import org.session.libsession.messaging.avatars.ProfileContactPhoto
import org.session.libsession.messaging.mentions.MentionsManager
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.mentions.MentionsManager
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.utilities.AvatarPlaceholderGenerator
import org.thoughtcrime.securesms.mms.GlideRequests

View File

@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.mms;
import android.content.Context;
import org.session.libsignal.service.loki.api.fileserver.FileServerAPI;
import org.session.libsession.messaging.file_server.FileServerAPI;
public class PushMediaConstraints extends MediaConstraints {

View File

@ -1,5 +1,6 @@
package org.session.libsession.database
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.utilities.DotNetAPI
@ -30,7 +31,6 @@ interface MessageDataProvider {
fun updateAttachmentAfterUploadSucceeded(attachmentId: Long, attachmentStream: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: DotNetAPI.UploadResult)
fun updateAttachmentAfterUploadFailed(attachmentId: Long)
// Quotes
fun getMessageForQuote(timestamp: Long, author: Address): Pair<Long, Boolean>?
fun getAttachmentsAndLinkPreviewFor(mmsId: Long): List<Attachment>
fun getMessageBodyFor(timestamp: Long, author: String): String
@ -38,4 +38,5 @@ interface MessageDataProvider {
fun getAttachmentIDsFor(messageID: Long): List<Long>
fun getLinkPreviewAttachmentIDFor(messageID: Long): Long?
fun getOpenGroup(threadID: Long): OpenGroup?
}

View File

@ -1,25 +0,0 @@
package org.session.libsession.messaging
import android.content.Context
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.service.loki.api.crypto.SessionProtocol
class MessagingConfiguration(
val context: Context,
val storage: StorageProtocol,
val messageDataProvider: MessageDataProvider,
val sessionProtocol: SessionProtocol)
{
companion object {
lateinit var shared: MessagingConfiguration
fun configure(context: Context,
storage: StorageProtocol,
messageDataProvider: MessageDataProvider,
sessionProtocol: SessionProtocol
) {
if (Companion::shared.isInitialized) { return }
shared = MessagingConfiguration(context, storage, messageDataProvider, sessionProtocol)
}
}
}

View File

@ -0,0 +1,26 @@
package org.session.libsession.messaging
import android.content.Context
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.service.loki.api.crypto.SessionProtocol
class MessagingModuleConfiguration(
val context: Context,
val storage: StorageProtocol,
val messageDataProvider: MessageDataProvider,
val sessionProtocol: SessionProtocol)
{
companion object {
lateinit var shared: MessagingModuleConfiguration
fun configure(context: Context,
storage: StorageProtocol,
messageDataProvider: MessageDataProvider,
sessionProtocol: SessionProtocol
) {
if (Companion::shared.isInitialized) { return }
shared = MessagingModuleConfiguration(context, storage, messageDataProvider, sessionProtocol)
}
}
}

View File

@ -9,12 +9,12 @@ import org.session.libsession.messaging.jobs.MessageSendJob
import org.session.libsession.messaging.messages.control.ConfigurationMessage
import org.session.libsession.messaging.messages.visible.Attachment
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.opengroups.OpenGroup
import org.session.libsession.messaging.opengroups.OpenGroupV2
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.dataextraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.GroupRecord
@ -22,7 +22,6 @@ import org.session.libsession.messaging.threads.recipients.Recipient.RecipientSe
import org.session.libsignal.libsignal.ecc.ECKeyPair
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
import org.session.libsignal.service.api.messages.SignalServiceGroup
import org.session.libsignal.service.internal.push.SignalServiceProtos
interface StorageProtocol {

View File

@ -1,6 +1,5 @@
package org.session.libsession.messaging.avatars;
import android.content.Context;
import androidx.annotation.NonNull;

View File

@ -1,6 +1,5 @@
package org.session.libsession.messaging.avatars;
import android.content.Context;
import android.net.Uri;
@ -19,5 +18,4 @@ public interface ContactPhoto extends Key {
@Nullable Uri getUri(@NonNull Context context);
boolean isProfilePhoto();
}

View File

@ -7,5 +7,4 @@ public interface FallbackContactPhoto {
public Drawable asDrawable(Context context, int color);
public Drawable asDrawable(Context context, int color, boolean inverted);
}

View File

@ -19,7 +19,6 @@ import org.session.libsession.utilities.ViewUtil;
import java.util.regex.Pattern;
public class GeneratedContactPhoto implements FallbackContactPhoto {
private static final Pattern PATTERN = Pattern.compile("[^\\p{L}\\p{Nd}\\p{S}]+");

View File

@ -1,13 +1,12 @@
package org.session.libsession.messaging.avatars;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.session.libsession.messaging.MessagingConfiguration;
import org.session.libsession.messaging.MessagingModuleConfiguration;
import org.session.libsession.messaging.StorageProtocol;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.threads.GroupRecord;
@ -32,7 +31,7 @@ public class GroupRecordContactPhoto implements ContactPhoto {
@Override
public InputStream openInputStream(Context context) throws IOException {
StorageProtocol groupDatabase = MessagingConfiguration.shared.getStorage();
StorageProtocol groupDatabase = MessagingModuleConfiguration.shared.getStorage();
Optional<GroupRecord> groupRecord = Optional.of(groupDatabase.getGroup(address.toGroupString()));
if (groupRecord.isPresent() && groupRecord.get().getAvatar() != null) {

View File

@ -1,6 +1,5 @@
package org.session.libsession.messaging.avatars;
import android.content.Context;
import android.net.Uri;

View File

@ -1,6 +1,5 @@
package org.session.libsession.messaging.avatars;
import android.content.Context;
import android.net.Uri;

View File

@ -1,17 +1,16 @@
package org.session.libsession.messaging.fileserver
package org.session.libsession.messaging.file_server
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.map
import okhttp3.Request
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsession.snode.OnionRequestAPI
import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.JsonUtil
import org.session.libsignal.service.loki.api.onionrequests.OnionRequestAPI
import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol
import org.session.libsignal.service.loki.utilities.*
import java.net.URL
import java.util.concurrent.ConcurrentHashMap
class FileServerAPI(public val server: String, userPublicKey: String, userPrivateKey: ByteArray, private val database: LokiAPIDatabaseProtocol) : DotNetAPI() {

View File

@ -1,9 +1,9 @@
package org.session.libsession.messaging.jobs
import okhttp3.HttpUrl
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.fileserver.FileServerAPI
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.file_server.FileServerAPI
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsignal.service.api.crypto.AttachmentCipherInputStream
@ -13,13 +13,10 @@ import java.io.File
import java.io.FileInputStream
class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
private val MAX_ATTACHMENT_SIZE = 10 * 1024 * 1024
// Error
internal sealed class Error(val description: String) : Exception(description) {
object NoAttachment : Error("No such attachment.")
@ -31,39 +28,39 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
companion object {
val KEY: String = "AttachmentDownloadJob"
//keys used for database storage purpose
// Keys used for database storage
private val KEY_ATTACHMENT_ID = "attachment_id"
private val KEY_TS_INCOMING_MESSAGE_ID = "tsIncoming_message_id"
}
override fun execute() {
val handleFailure: (java.lang.Exception) -> Unit = { exception ->
if (exception is Error && exception == Error.NoAttachment) {
MessagingConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
if (exception == Error.NoAttachment) {
MessagingModuleConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
this.handlePermanentFailure(exception)
} else if (exception is DotNetAPI.Error && exception == DotNetAPI.Error.ParsingFailed) {
} else if (exception == DotNetAPI.Error.ParsingFailed) {
// No need to retry if the response is invalid. Most likely this means we (incorrectly)
// got a "Cannot GET ..." error from the file server.
MessagingConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
MessagingModuleConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
this.handlePermanentFailure(exception)
} else {
this.handleFailure(exception)
}
}
try {
val messageDataProvider = MessagingConfiguration.shared.messageDataProvider
val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider
val attachment = messageDataProvider.getDatabaseAttachment(attachmentID)
?: return handleFailure(Error.NoAttachment)
messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachmentID, this.databaseMessageID)
val tempFile = createTempFile()
val threadId = MessagingConfiguration.shared.storage.getThreadIdForMms(databaseMessageID)
val openGroupV2 = MessagingConfiguration.shared.storage.getV2OpenGroup(threadId.toString())
val threadId = MessagingModuleConfiguration.shared.storage.getThreadIdForMms(databaseMessageID)
val openGroupV2 = MessagingModuleConfiguration.shared.storage.getV2OpenGroup(threadId.toString())
val stream = if (openGroupV2 == null) {
FileServerAPI.shared.downloadFile(tempFile, attachment.url, MAX_ATTACHMENT_SIZE, null)
FileServerAPI.shared.downloadFile(tempFile, attachment.url, null)
// DECRYPTION
// Assume we're retrieving an attachment for an open group server if the digest is not set
if (attachment.digest?.size ?: 0 == 0 || attachment.key.isNullOrEmpty()) FileInputStream(tempFile)
@ -98,17 +95,15 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
}
private fun createTempFile(): File {
val file = File.createTempFile("push-attachment", "tmp", MessagingConfiguration.shared.context.cacheDir)
val file = File.createTempFile("push-attachment", "tmp", MessagingModuleConfiguration.shared.context.cacheDir)
file.deleteOnExit()
return file
}
//database functions
override fun serialize(): Data {
return Data.Builder().putLong(KEY_ATTACHMENT_ID, attachmentID)
.putLong(KEY_TS_INCOMING_MESSAGE_ID, databaseMessageID)
.build();
.putLong(KEY_TS_INCOMING_MESSAGE_ID, databaseMessageID)
.build();
}
override fun getFactoryKey(): String {

View File

@ -3,10 +3,10 @@ package org.session.libsession.messaging.jobs
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.fileserver.FileServerAPI
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.file_server.FileServerAPI
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsignal.service.api.crypto.AttachmentCipherOutputStream
@ -19,7 +19,6 @@ import org.session.libsignal.service.loki.utilities.PlaintextOutputStreamFactory
import org.session.libsignal.utilities.logging.Log
class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val message: Message, val messageSendJobID: String) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
@ -35,9 +34,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
val TAG = AttachmentUploadJob::class.simpleName
val KEY: String = "AttachmentUploadJob"
val maxFailureCount: Int = 20
//keys used for database storage purpose
// Keys used for database storage
private val KEY_ATTACHMENT_ID = "attachment_id"
private val KEY_THREAD_ID = "thread_id"
private val KEY_MESSAGE = "message"
@ -46,22 +43,18 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
override fun execute() {
try {
val attachment = MessagingConfiguration.shared.messageDataProvider.getScaledSignalAttachmentStream(attachmentID)
?: return handleFailure(Error.NoAttachment)
val attachment = MessagingModuleConfiguration.shared.messageDataProvider.getScaledSignalAttachmentStream(attachmentID)
?: return handleFailure(Error.NoAttachment)
var server = FileServerAPI.shared.server
var shouldEncrypt = true
val usePadding = false
val openGroup = MessagingConfiguration.shared.storage.getOpenGroup(threadID)
val openGroupV2 = MessagingConfiguration.shared.storage.getV2OpenGroup(threadID)
openGroup?.let {
server = it.server
shouldEncrypt = false
}
openGroupV2?.let {
server = it.server
shouldEncrypt = false
}
val openGroupV2 = MessagingModuleConfiguration.shared.storage.getV2OpenGroup(threadID)
val openGroup = MessagingModuleConfiguration.shared.storage.getOpenGroup(threadID)
val server = openGroup?.let {
it.server
} ?: openGroupV2?.let {
it.server
} ?: FileServerAPI.shared.server
val shouldEncrypt = (openGroup == null && openGroupV2 == null) // Encrypt if this isn't an open group
val attachmentKey = Util.getSecretBytes(64)
val paddedLength = if (usePadding) PaddingInputStream.getPaddedSize(attachment.length) else attachment.length
@ -77,9 +70,8 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
DotNetAPI.UploadResult(result, "${openGroupV2.server}/files/$result", byteArrayOf())
}
handleSuccess(attachment, attachmentKey, uploadResult)
} catch (e: java.lang.Exception) {
if (e is Error && e == Error.NoAttachment) {
if (e == Error.NoAttachment) {
this.handlePermanentFailure(e)
} else if (e is DotNetAPI.Error && !e.isRetryable) {
this.handlePermanentFailure(e)
@ -87,33 +79,32 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
this.handleFailure(e)
}
}
}
private fun handleSuccess(attachment: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: DotNetAPI.UploadResult) {
Log.w(TAG, "Attachment uploaded successfully.")
delegate?.handleJobSucceeded(this)
MessagingConfiguration.shared.messageDataProvider.updateAttachmentAfterUploadSucceeded(attachmentID, attachment, attachmentKey, uploadResult)
MessagingConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID)
MessagingModuleConfiguration.shared.messageDataProvider.updateAttachmentAfterUploadSucceeded(attachmentID, attachment, attachmentKey, uploadResult)
MessagingModuleConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID)
}
private fun handlePermanentFailure(e: Exception) {
Log.w(TAG, "Attachment upload failed permanently due to error: $this.")
delegate?.handleJobFailedPermanently(this, e)
MessagingConfiguration.shared.messageDataProvider.updateAttachmentAfterUploadFailed(attachmentID)
MessagingModuleConfiguration.shared.messageDataProvider.updateAttachmentAfterUploadFailed(attachmentID)
failAssociatedMessageSendJob(e)
}
private fun handleFailure(e: Exception) {
Log.w(TAG, "Attachment upload failed due to error: $this.")
delegate?.handleJobFailed(this, e)
if (failureCount + 1 == AttachmentUploadJob.maxFailureCount) {
if (failureCount + 1 == maxFailureCount) {
failAssociatedMessageSendJob(e)
}
}
private fun failAssociatedMessageSendJob(e: Exception) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val messageSendJob = storage.getMessageSendJob(messageSendJobID)
MessageSender.handleFailedMessageSend(this.message, e)
if (messageSendJob != null) {
@ -121,10 +112,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
}
}
//database functions
override fun serialize(): Data {
//serialize Message property
val kryo = Kryo()
kryo.isRegistrationRequired = false
val serializedMessage = ByteArray(4096)
@ -132,10 +120,10 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
kryo.writeObject(output, message)
output.close()
return Data.Builder().putLong(KEY_ATTACHMENT_ID, attachmentID)
.putString(KEY_THREAD_ID, threadID)
.putByteArray(KEY_MESSAGE, serializedMessage)
.putString(KEY_MESSAGE_SEND_JOB_ID, messageSendJobID)
.build();
.putString(KEY_THREAD_ID, threadID)
.putByteArray(KEY_MESSAGE, serializedMessage)
.putString(KEY_MESSAGE_SEND_JOB_ID, messageSendJobID)
.build();
}
override fun getFactoryKey(): String {
@ -143,9 +131,9 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
}
class Factory: Job.Factory<AttachmentUploadJob> {
override fun create(data: Data): AttachmentUploadJob {
val serializedMessage = data.getByteArray(KEY_MESSAGE)
//deserialize Message property
val kryo = Kryo()
val input = Input(serializedMessage)
val message: Message = kryo.readObject(input, Message::class.java)

View File

@ -12,7 +12,6 @@ import org.session.libsession.utilities.ParcelableUtil;
import java.util.HashMap;
import java.util.Map;
// TODO AC: For now parcelable objects utilize byteArrays field to store their data into.
// Introduce a dedicated Map<String, byte[]> field specifically for parcelable needs.
public class Data {

View File

@ -8,15 +8,13 @@ interface Job {
val maxFailureCount: Int
companion object {
//keys used for database storage purpose
// Keys used for database storage
private val KEY_ID = "id"
private val KEY_FAILURE_COUNT = "failure_count"
}
fun execute()
//database functions
fun serialize(): Data
/**

View File

@ -1,6 +1,7 @@
package org.session.libsession.messaging.jobs
interface JobDelegate {
fun handleJobSucceeded(job: Job)
fun handleJobFailed(job: Job, error: Exception)
fun handleJobFailedPermanently(job: Job, error: Exception)

View File

@ -3,7 +3,7 @@ package org.session.libsession.messaging.jobs
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsignal.utilities.logging.Log
import java.util.*
import java.util.concurrent.ConcurrentHashMap
@ -14,20 +14,18 @@ import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToLong
class JobQueue : JobDelegate {
private var hasResumedPendingJobs = false // Just for debugging
private val jobTimestampMap = ConcurrentHashMap<Long, AtomicInteger>()
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val multiDispatcher = Executors.newFixedThreadPool(2).asCoroutineDispatcher()
private val scope = GlobalScope + SupervisorJob()
private val queue = Channel<Job>(UNLIMITED)
val timer = Timer()
init {
// process jobs
// Process jobs
scope.launch(dispatcher) {
while (isActive) {
queue.receive().let { job ->
@ -64,14 +62,14 @@ class JobQueue : JobDelegate {
private fun addWithoutExecuting(job: Job) {
// When adding multiple jobs in rapid succession, timestamps might not be good enough as a unique ID. To
// deal with this we keep track of the number of jobs with a given timestamp and that to the end of the
// deal with this we keep track of the number of jobs with a given timestamp and add that to the end of the
// timestamp to make it a unique ID. We can't use a random number because we do still want to keep track
// of the order in which the jobs were added.
val currentTime = System.currentTimeMillis()
jobTimestampMap.putIfAbsent(currentTime, AtomicInteger())
job.id = currentTime.toString() + jobTimestampMap[currentTime]!!.getAndIncrement().toString()
MessagingConfiguration.shared.storage.persistJob(job)
MessagingModuleConfiguration.shared.storage.persistJob(job)
}
fun resumePendingJobs() {
@ -82,21 +80,21 @@ class JobQueue : JobDelegate {
hasResumedPendingJobs = true
val allJobTypes = listOf(AttachmentDownloadJob.KEY, AttachmentDownloadJob.KEY, MessageReceiveJob.KEY, MessageSendJob.KEY, NotifyPNServerJob.KEY)
allJobTypes.forEach { type ->
val allPendingJobs = MessagingConfiguration.shared.storage.getAllPendingJobs(type)
val allPendingJobs = MessagingModuleConfiguration.shared.storage.getAllPendingJobs(type)
allPendingJobs.sortedBy { it.id }.forEach { job ->
Log.i("Jobs", "Resuming pending job of type: ${job::class.simpleName}.")
queue.offer(job) // offer always called on unlimited capacity
queue.offer(job) // Offer always called on unlimited capacity
}
}
}
override fun handleJobSucceeded(job: Job) {
MessagingConfiguration.shared.storage.markJobAsSucceeded(job)
MessagingModuleConfiguration.shared.storage.markJobAsSucceeded(job)
}
override fun handleJobFailed(job: Job, error: Exception) {
job.failureCount += 1
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
if (storage.isJobCanceled(job)) { return Log.i("Jobs", "${job::class.simpleName} canceled.")}
storage.persistJob(job)
if (job.failureCount == job.maxFailureCount) {
@ -113,7 +111,7 @@ class JobQueue : JobDelegate {
override fun handleJobFailedPermanently(job: Job, error: Exception) {
job.failureCount += 1
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
storage.persistJob(job)
storage.markJobAsFailed(job)
}

View File

@ -7,7 +7,6 @@ import org.session.libsession.messaging.sending_receiving.handle
import org.session.libsignal.utilities.logging.Log
class MessageReceiveJob(val data: ByteArray, val isBackgroundPoll: Boolean, val openGroupMessageServerID: Long? = null, val openGroupID: String? = null) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
@ -20,7 +19,7 @@ class MessageReceiveJob(val data: ByteArray, val isBackgroundPoll: Boolean, val
private val RECEIVE_LOCK = Object()
//keys used for database storage purpose
// Keys used for database storage
private val KEY_DATA = "data"
private val KEY_IS_BACKGROUND_POLL = "is_background_poll"
private val KEY_OPEN_GROUP_MESSAGE_SERVER_ID = "openGroupMessageServerID"
@ -68,8 +67,6 @@ class MessageReceiveJob(val data: ByteArray, val isBackgroundPoll: Boolean, val
delegate?.handleJobFailed(this, e)
}
//database functions
override fun serialize(): Data {
val builder = Data.Builder().putByteArray(KEY_DATA, data)
.putBoolean(KEY_IS_BACKGROUND_POLL, isBackgroundPoll)
@ -83,6 +80,7 @@ class MessageReceiveJob(val data: ByteArray, val isBackgroundPoll: Boolean, val
}
class Factory: Job.Factory<MessageReceiveJob> {
override fun create(data: Data): MessageReceiveJob {
return MessageReceiveJob(data.getByteArray(KEY_DATA), data.getBoolean(KEY_IS_BACKGROUND_POLL), data.getLong(KEY_OPEN_GROUP_MESSAGE_SERVER_ID), data.getString(KEY_OPEN_GROUP_ID))
}

View File

@ -3,7 +3,7 @@ package org.session.libsession.messaging.jobs
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Destination
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.visible.VisibleMessage
@ -11,7 +11,6 @@ import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsignal.utilities.logging.Log
class MessageSendJob(val message: Message, val destination: Destination) : Job {
override var delegate: JobDelegate? = null
override var id: String? = null
override var failureCount: Int = 0
@ -22,13 +21,13 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
val TAG = MessageSendJob::class.simpleName
val KEY: String = "MessageSendJob"
//keys used for database storage purpose
// Keys used for database storage
private val KEY_MESSAGE = "message"
private val KEY_DESTINATION = "destination"
}
override fun execute() {
val messageDataProvider = MessagingConfiguration.shared.messageDataProvider
val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider
val message = message as? VisibleMessage
message?.let {
if(!messageDataProvider.isOutgoingMessage(message.sentTimestamp!!)) return // The message has been deleted
@ -39,7 +38,7 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
val attachments = attachmentIDs.mapNotNull { messageDataProvider.getDatabaseAttachment(it) }
val attachmentsToUpload = attachments.filter { it.url.isNullOrEmpty() }
attachmentsToUpload.forEach {
if (MessagingConfiguration.shared.storage.getAttachmentUploadJob(it.attachmentId.rowId) != null) {
if (MessagingModuleConfiguration.shared.storage.getAttachmentUploadJob(it.attachmentId.rowId) != null) {
// Wait for it to finish
} else {
val job = AttachmentUploadJob(it.attachmentId.rowId, message.threadID!!.toString(), message, id!!)
@ -72,15 +71,12 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
Log.w(TAG, "Failed to send $message::class.simpleName.")
val message = message as? VisibleMessage
message?.let {
if(!MessagingConfiguration.shared.messageDataProvider.isOutgoingMessage(message.sentTimestamp!!)) return // The message has been deleted
if(!MessagingModuleConfiguration.shared.messageDataProvider.isOutgoingMessage(message.sentTimestamp!!)) return // The message has been deleted
}
delegate?.handleJobFailed(this, error)
}
//database functions
override fun serialize(): Data {
//serialize Message and Destination properties
val kryo = Kryo()
kryo.isRegistrationRequired = false
val output = Output(ByteArray(4096), -1) // maxBufferSize '-1' will dynamically grow internally if we run out of room serializing the message
@ -92,8 +88,8 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
output.close()
val serializedDestination = output.toBytes()
return Data.Builder().putByteArray(KEY_MESSAGE, serializedMessage)
.putByteArray(KEY_DESTINATION, serializedDestination)
.build();
.putByteArray(KEY_DESTINATION, serializedDestination)
.build();
}
override fun getFactoryKey(): String {
@ -101,10 +97,10 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
}
class Factory: Job.Factory<MessageSendJob> {
override fun create(data: Data): MessageSendJob {
val serializedMessage = data.getByteArray(KEY_MESSAGE)
val serializedDestination = data.getByteArray(KEY_DESTINATION)
//deserialize Message and Destination properties
val kryo = Kryo()
var input = Input(serializedMessage)
val message = kryo.readClassAndObject(input) as Message

View File

@ -26,7 +26,7 @@ class NotifyPNServerJob(val message: SnodeMessage) : Job {
companion object {
val KEY: String = "NotifyPNServerJob"
//keys used for database storage purpose
// Keys used for database storage
private val KEY_MESSAGE = "message"
}
@ -61,18 +61,14 @@ class NotifyPNServerJob(val message: SnodeMessage) : Job {
delegate?.handleJobFailed(this, error)
}
//database functions
override fun serialize(): Data {
//serialize SnodeMessage property
val kryo = Kryo()
kryo.isRegistrationRequired = false
val serializedMessage = ByteArray(4096)
val output = Output(serializedMessage)
kryo.writeObject(output, message)
output.close()
return Data.Builder().putByteArray(KEY_MESSAGE, serializedMessage)
.build();
return Data.Builder().putByteArray(KEY_MESSAGE, serializedMessage).build();
}
override fun getFactoryKey(): String {
@ -80,9 +76,9 @@ class NotifyPNServerJob(val message: SnodeMessage) : Job {
}
class Factory: Job.Factory<NotifyPNServerJob> {
override fun create(data: Data): NotifyPNServerJob {
val serializedMessage = data.getByteArray(KEY_MESSAGE)
//deserialize SnodeMessage property
val kryo = Kryo()
val input = Input(serializedMessage)
val message: SnodeMessage = kryo.readObject(input, SnodeMessage::class.java)

View File

@ -1,7 +1,5 @@
package org.session.libsession.messaging.jobs
import java.util.*
class SessionJobInstantiator(private val jobFactories: Map<String, Job.Factory<out Job>>) {
fun instantiate(jobFactoryKey: String, data: Data): Job {

View File

@ -1,7 +1,5 @@
package org.session.libsession.messaging.jobs
import java.util.*
class SessionJobManagerFactories {
companion object {

View File

@ -1,20 +1,20 @@
package org.session.libsession.utilities.mentions
package org.session.libsession.messaging.mentions
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.utilities.mentions.Mention
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsignal.service.loki.database.LokiThreadDatabaseProtocol
import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol
class MentionsManager(private val userPublicKey: String, private val threadDatabase: LokiThreadDatabaseProtocol,
private val userDatabase: LokiUserDatabaseProtocol) {
class MentionsManager(private val userPublicKey: String, private val userDatabase: LokiUserDatabaseProtocol) {
var userPublicKeyCache = mutableMapOf<Long, Set<String>>() // Thread ID to set of user hex encoded public keys
companion object {
lateinit var shared: MentionsManager
public lateinit var shared: MentionsManager
fun configureIfNeeded(userPublicKey: String, threadDatabase: LokiThreadDatabaseProtocol, userDatabase: LokiUserDatabaseProtocol) {
public fun configureIfNeeded(userPublicKey: String, userDatabase: LokiUserDatabaseProtocol) {
if (::shared.isInitialized) { return; }
shared = MentionsManager(userPublicKey, threadDatabase, userDatabase)
shared = MentionsManager(userPublicKey, userDatabase)
}
}
@ -31,15 +31,11 @@ class MentionsManager(private val userPublicKey: String, private val threadDatab
// Prepare
val cache = userPublicKeyCache[threadID] ?: return listOf()
// Gather candidates
val storage = MessagingConfiguration.shared.storage
val publicChat = threadDatabase.getPublicChat(threadID)
val openGroupV2 = storage.getV2OpenGroup(threadID.toString())
val publicChat = MessagingModuleConfiguration.shared.messageDataProvider.getOpenGroup(threadID)
var candidates: List<Mention> = cache.mapNotNull { publicKey ->
val displayName: String?
if (publicChat != null) {
displayName = userDatabase.getServerDisplayName(publicChat.id, publicKey)
} else if (openGroupV2 != null) {
displayName = userDatabase.getServerDisplayName(openGroupV2.id, publicKey)
} else {
displayName = userDatabase.getDisplayName(publicKey)
}

View File

@ -1,12 +1,14 @@
package org.session.libsession.messaging.messages
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.messaging.open_groups.OpenGroup
import org.session.libsession.messaging.threads.Address
import org.session.libsession.utilities.GroupUtil
import org.session.libsignal.service.loki.utilities.toHexString
typealias OpenGroupModel = org.session.libsession.messaging.opengroups.OpenGroup
typealias OpenGroupV2Model = org.session.libsession.messaging.opengroups.OpenGroupV2
typealias OpenGroupModel = OpenGroup
typealias OpenGroupV2Model = OpenGroupV2
sealed class Destination {
@ -35,7 +37,7 @@ sealed class Destination {
ClosedGroup(groupPublicKey)
}
address.isOpenGroup -> {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val threadID = storage.getThreadID(address.contactIdentifier())!!
when (val openGroup = storage.getOpenGroup(threadID) ?: storage.getV2OpenGroup(threadID)) {
is OpenGroupModel -> OpenGroup(openGroup.channel, openGroup.server)

View File

@ -5,7 +5,6 @@ import org.session.libsession.utilities.GroupUtil
import org.session.libsignal.service.internal.push.SignalServiceProtos
abstract class Message {
var id: Long? = null
var threadID: Long? = null
var sentTimestamp: Long? = null
@ -15,10 +14,9 @@ abstract class Message {
var groupPublicKey: String? = null
var openGroupServerMessageID: Long? = null
open val ttl: Long = 2 * 24 * 60 * 60 * 1000
open val ttl: Long = 14 * 24 * 60 * 60 * 1000
open val isSelfSendValid: Boolean = false
// validation
open fun isValid(): Boolean {
sentTimestamp?.let {
if (it <= 0) return false

View File

@ -1,7 +1,7 @@
package org.session.libsession.messaging.messages.control
import com.google.protobuf.ByteString
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.GroupUtil
@ -19,8 +19,8 @@ class ClosedGroupControlMessage() : ControlMessage() {
override val ttl: Long = run {
when (kind) {
is Kind.EncryptionKeyPair -> return@run 4 * 24 * 60 * 60 * 1000
else -> return@run 2 * 24 * 60 * 60 * 1000
is Kind.EncryptionKeyPair -> 14 * 24 * 60 * 60 * 1000
else -> 14 * 24 * 60 * 60 * 1000
}
}
@ -28,15 +28,10 @@ class ClosedGroupControlMessage() : ControlMessage() {
var kind: Kind? = null
// Kind enum
sealed class Kind {
class New(var publicKey: ByteString, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<ByteString>, var admins: List<ByteString>) : Kind() {
internal constructor(): this(ByteString.EMPTY, "", null, listOf(), listOf())
}
/// - Note: Deprecated in favor of more explicit group updates.
class Update(var name: String, var members: List<ByteString>) : Kind() {
internal constructor(): this("", listOf())
}
/// An encryption key pair encrypted for each member individually.
///
/// - Note: `publicKey` is only set when an encryption key pair is sent in a one-to-one context (i.e. not in a group).
@ -53,18 +48,15 @@ class ClosedGroupControlMessage() : ControlMessage() {
internal constructor(): this(listOf())
}
class MemberLeft() : Kind()
class EncryptionKeyPairRequest(): Kind()
val description: String =
when(this) {
is New -> "new"
is Update -> "update"
is EncryptionKeyPair -> "encryptionKeyPair"
is NameChange -> "nameChange"
is MembersAdded -> "membersAdded"
is MembersRemoved -> "membersRemoved"
is MemberLeft -> "memberLeft"
is EncryptionKeyPairRequest -> "encryptionKeyPairRequest"
}
}
@ -75,12 +67,11 @@ class ClosedGroupControlMessage() : ControlMessage() {
if (!proto.hasDataMessage() || !proto.dataMessage.hasClosedGroupControlMessage()) return null
val closedGroupControlMessageProto = proto.dataMessage?.closedGroupControlMessage!!
val kind: Kind
when(closedGroupControlMessageProto.type) {
when (closedGroupControlMessageProto.type) {
DataMessage.ClosedGroupControlMessage.Type.NEW -> {
val publicKey = closedGroupControlMessageProto.publicKey ?: return null
val name = closedGroupControlMessageProto.name ?: return null
val encryptionKeyPairAsProto = closedGroupControlMessageProto.encryptionKeyPair ?: return null
try {
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray()), DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
kind = Kind.New(publicKey, name, encryptionKeyPair, closedGroupControlMessageProto.membersList, closedGroupControlMessageProto.adminsList)
@ -89,10 +80,6 @@ class ClosedGroupControlMessage() : ControlMessage() {
return null
}
}
DataMessage.ClosedGroupControlMessage.Type.UPDATE -> {
val name = closedGroupControlMessageProto.name ?: return null
kind = Kind.Update(name, closedGroupControlMessageProto.membersList)
}
DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR -> {
val publicKey = closedGroupControlMessageProto.publicKey
val wrappers = closedGroupControlMessageProto.wrappersList.mapNotNull { KeyPairWrapper.fromProto(it) }
@ -111,35 +98,28 @@ class ClosedGroupControlMessage() : ControlMessage() {
DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT -> {
kind = Kind.MemberLeft()
}
DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR_REQUEST -> {
kind = Kind.EncryptionKeyPairRequest()
}
}
return ClosedGroupControlMessage(kind)
}
}
// constructor
internal constructor(kind: Kind?) : this() {
this.kind = kind
}
// validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
val kind = kind ?: return false
return when(kind) {
is Kind.New -> {
!kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair!!.publicKey != null
&& kind.encryptionKeyPair!!.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty()
&& kind.encryptionKeyPair!!.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty()
}
is Kind.Update -> kind.name.isNotEmpty()
is Kind.EncryptionKeyPair -> true
is Kind.NameChange -> kind.name.isNotEmpty()
is Kind.MembersAdded -> kind.members.isNotEmpty()
is Kind.MembersRemoved -> kind.members.isNotEmpty()
is Kind.MemberLeft -> true
is Kind.EncryptionKeyPairRequest -> true
}
}
@ -163,11 +143,6 @@ class ClosedGroupControlMessage() : ControlMessage() {
closedGroupControlMessage.addAllMembers(kind.members)
closedGroupControlMessage.addAllAdmins(kind.admins)
}
is Kind.Update -> {
closedGroupControlMessage.type = DataMessage.ClosedGroupControlMessage.Type.UPDATE
closedGroupControlMessage.name = kind.name
closedGroupControlMessage.addAllMembers(kind.members)
}
is Kind.EncryptionKeyPair -> {
closedGroupControlMessage.type = DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR
closedGroupControlMessage.publicKey = kind.publicKey
@ -188,9 +163,6 @@ class ClosedGroupControlMessage() : ControlMessage() {
is Kind.MemberLeft -> {
closedGroupControlMessage.type = DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT
}
is Kind.EncryptionKeyPairRequest -> {
// TODO: closedGroupControlMessage.type = SignalServiceProtos.ClosedGroupUpdateV2.Type.ENCRYPTION_KEY_PAIR_REQUEST
}
}
val contentProto = SignalServiceProtos.Content.newBuilder()
val dataMessageProto = DataMessage.newBuilder()
@ -199,8 +171,8 @@ class ClosedGroupControlMessage() : ControlMessage() {
setGroupContext(dataMessageProto)
// Expiration timer
// TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation
// if it receives a message without the current expiration timer value attached to it...
dataMessageProto.expireTimer = Recipient.from(MessagingConfiguration.shared.context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(recipient!!)), false).expireMessages
// if it receives a message without the current expiration timer value attached to it...
dataMessageProto.expireTimer = Recipient.from(MessagingModuleConfiguration.shared.context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(recipient!!)), false).expireMessages
contentProto.dataMessage = dataMessageProto.build()
return contentProto.build()
} catch (e: Exception) {

View File

@ -1,7 +1,7 @@
package org.session.libsession.messaging.messages.control
import com.google.protobuf.ByteString
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.threads.Address
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.TextSecurePreferences
@ -26,13 +26,14 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
}
companion object {
fun fromProto(proto: SignalServiceProtos.ConfigurationMessage.ClosedGroup): ClosedGroup? {
if (!proto.hasPublicKey() || !proto.hasName() || !proto.hasEncryptionKeyPair()) return null
val publicKey = proto.publicKey.toByteArray().toHexString()
val name = proto.name
val encryptionKeyPairAsProto = proto.encryptionKeyPair
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray().removing05PrefixIfNeeded()),
DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
val members = proto.membersList.map { it.toByteArray().toHexString() }
val admins = proto.adminsList.map { it.toByteArray().toHexString() }
return ClosedGroup(publicKey, name, encryptionKeyPair, members, admins)
@ -58,6 +59,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
internal constructor(): this("", "", null, null)
companion object {
fun fromProto(proto: SignalServiceProtos.ConfigurationMessage.Contact): Contact? {
if (!proto.hasName() || !proto.hasProfileKey()) return null
val publicKey = proto.publicKey.toByteArray().toHexString()
@ -87,7 +89,6 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
}
}
override val ttl: Long = 4 * 24 * 60 * 60 * 1000
override val isSelfSendValid: Boolean = true
companion object {
@ -95,7 +96,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
fun getCurrent(contacts: List<Contact>): ConfigurationMessage? {
val closedGroups = mutableListOf<ClosedGroup>()
val openGroups = mutableListOf<String>()
val sharedConfig = MessagingConfiguration.shared
val sharedConfig = MessagingModuleConfiguration.shared
val storage = sharedConfig.storage
val context = sharedConfig.context
val displayName = TextSecurePreferences.getProfileName(context) ?: return null

View File

@ -6,13 +6,12 @@ import org.session.libsignal.utilities.logging.Log
class DataExtractionNotification(): ControlMessage() {
var kind: Kind? = null
// Kind enum
sealed class Kind {
class Screenshot() : Kind()
class MediaSaved(val timestamp: Long) : Kind()
val description: String =
when(this) {
when (this) {
is Screenshot -> "screenshot"
is MediaSaved -> "mediaSaved"
}
@ -35,12 +34,10 @@ class DataExtractionNotification(): ControlMessage() {
}
}
//constructor
internal constructor(kind: Kind) : this() {
this.kind = kind
}
// MARK: Validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
val kind = kind ?: return false

View File

@ -1,12 +1,11 @@
package org.session.libsession.messaging.messages.control
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
class ExpirationTimerUpdate() : ControlMessage() {
/// In the case of a sync message, the public key of the person the message was targeted at.
/// - Note: `nil` if this isn't a sync message.
var syncTarget: String? = null
@ -27,7 +26,6 @@ class ExpirationTimerUpdate() : ControlMessage() {
}
}
//constructor
internal constructor(syncTarget: String?, duration: Int) : this() {
this.syncTarget = syncTarget
this.duration = duration
@ -38,7 +36,6 @@ class ExpirationTimerUpdate() : ControlMessage() {
this.duration = duration
}
// validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
return duration != null
@ -58,7 +55,7 @@ class ExpirationTimerUpdate() : ControlMessage() {
dataMessageProto.syncTarget = syncTarget
}
// Group context
if (MessagingConfiguration.shared.storage.isClosedGroup(recipient!!)) {
if (MessagingModuleConfiguration.shared.storage.isClosedGroup(recipient!!)) {
try {
setGroupContext(dataMessageProto)
} catch(e: Exception) {

View File

@ -4,7 +4,6 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.utilities.logging.Log
class ReadReceipt() : ControlMessage() {
var timestamps: List<Long>? = null
companion object {
@ -19,12 +18,10 @@ class ReadReceipt() : ControlMessage() {
}
}
//constructor
internal constructor(timestamps: List<Long>?) : this() {
this.timestamps = timestamps
}
// validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
val timestamps = timestamps ?: return false

View File

@ -4,8 +4,8 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.utilities.logging.Log
class TypingIndicator() : ControlMessage() {
override val ttl: Long = 30 * 1000
var kind: Kind? = null
companion object {
const val TAG = "TypingIndicator"
@ -17,11 +17,8 @@ class TypingIndicator() : ControlMessage() {
}
}
// Kind enum
enum class Kind {
STARTED,
STOPPED,
;
STARTED, STOPPED;
companion object {
@JvmStatic
@ -40,14 +37,10 @@ class TypingIndicator() : ControlMessage() {
}
}
var kind: Kind? = null
//constructor
internal constructor(kind: Kind) : this() {
this.kind = kind
}
// validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
return kind != null

View File

@ -1,7 +1,5 @@
package org.session.libsession.messaging.messages.signal;
import static org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
public class IncomingGroupMessage extends IncomingTextMessage {
private final String groupID;

View File

@ -3,10 +3,10 @@ package org.session.libsession.messaging.messages.signal;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment;
import org.session.libsession.messaging.sending_receiving.dataextraction.DataExtractionNotificationInfoMessage;
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.utilities.GroupUtil;
import org.session.libsignal.libsignal.util.guava.Optional;

View File

@ -6,14 +6,10 @@ import androidx.annotation.Nullable;
import org.session.libsession.messaging.threads.DistributionTypes;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsignal.utilities.Base64;
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

View File

@ -9,7 +9,7 @@ import org.session.libsession.database.documents.IdentityKeyMismatch;
import org.session.libsession.database.documents.NetworkFailure;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.recipients.Recipient;

View File

@ -5,7 +5,7 @@ import androidx.annotation.Nullable;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.recipients.Recipient;

View File

@ -11,7 +11,6 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos
import java.io.File
class Attachment {
var fileName: String? = null
var contentType: String? = null
var key: ByteArray? = null
@ -23,6 +22,7 @@ class Attachment {
var url: String? = null
companion object {
fun fromProto(proto: SignalServiceProtos.AttachmentPointer): Attachment {
val result = Attachment()
result.fileName = proto.fileName
@ -88,7 +88,6 @@ class Attachment {
GENERIC
}
// validation
fun isValid(): Boolean {
// key and digest can be nil for open group attachments
return (contentType != null && kind != null && size != null && sizeInBytes != null && url != null)

View File

@ -1,17 +0,0 @@
package org.session.libsession.messaging.messages.visible
import org.session.libsession.database.MessageDataProvider
import org.session.libsignal.service.internal.push.SignalServiceProtos
class Contact() {
companion object {
fun fromProto(proto: SignalServiceProtos.Content): Contact? {
TODO("Not yet implemented")
}
}
fun toProto(): SignalServiceProtos.DataMessage.Contact? {
TODO("Not yet implemented")
}
}

View File

@ -1,12 +1,11 @@
package org.session.libsession.messaging.messages.visible
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview as SignalLinkPreiview
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview as SignalLinkPreiview
import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
class LinkPreview() {
var title: String? = null
var url: String? = null
var attachmentID: Long? = 0
@ -29,15 +28,12 @@ class LinkPreview() {
}
}
//constructor
internal constructor(title: String?, url: String, attachmentID: Long?) : this() {
this.title = title
this.url = url
this.attachmentID = attachmentID
}
// validation
fun isValid(): Boolean {
return (title != null && url != null && attachmentID != null)
}
@ -53,7 +49,7 @@ class LinkPreview() {
title?.let { linkPreviewProto.title = title }
val attachmentID = attachmentID
attachmentID?.let {
MessagingConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID)?.let {
MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID)?.let {
val attachmentProto = Attachment.createAttachmentPointer(it)
linkPreviewProto.image = attachmentProto
}

View File

@ -5,7 +5,6 @@ import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
class Profile() {
var displayName: String? = null
var profileKey: ByteArray? = null
var profilePictureURL: String? = null
@ -27,7 +26,6 @@ class Profile() {
}
}
//constructor
internal constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() {
this.displayName = displayName
this.profileKey = profileKey

View File

@ -1,14 +1,13 @@
package org.session.libsession.messaging.messages.visible
import com.goterl.lazycode.lazysodium.BuildConfig
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as SignalQuote
import org.session.libsignal.utilities.logging.Log
import org.session.libsignal.service.internal.push.SignalServiceProtos
class Quote() {
var timestamp: Long? = 0
var publicKey: String? = null
var text: String? = null
@ -34,7 +33,6 @@ class Quote() {
}
}
//constructor
internal constructor(timestamp: Long, publicKey: String, text: String?, attachmentID: Long?) : this() {
this.timestamp = timestamp
this.publicKey = publicKey
@ -42,7 +40,6 @@ class Quote() {
this.attachmentID = attachmentID
}
// validation
fun isValid(): Boolean {
return (timestamp != null && publicKey != null)
}
@ -70,7 +67,7 @@ class Quote() {
private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder) {
if (attachmentID == null) return
val attachment = MessagingConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID!!)
val attachment = MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID!!)
if (attachment == null) {
Log.w(TAG, "Ignoring invalid attachment for quoted message.")
return

View File

@ -1,7 +1,7 @@
package org.session.libsession.messaging.messages.visible
import com.goterl.lazycode.lazysodium.BuildConfig
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.threads.Address
@ -12,13 +12,11 @@ import org.session.libsignal.utilities.logging.Log
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
class VisibleMessage : Message() {
var syncTarget: String? = null
var text: String? = null
val attachmentIDs: MutableList<Long> = mutableListOf()
var quote: Quote? = null
var linkPreview: LinkPreview? = null
var contact: Contact? = null
var profile: Profile? = null
override val isSelfSendValid: Boolean = true
@ -60,10 +58,9 @@ class VisibleMessage : Message() {
}
fun isMediaMessage(): Boolean {
return attachmentIDs.isNotEmpty() || quote != null || linkPreview != null || contact != null
return attachmentIDs.isNotEmpty() || quote != null || linkPreview != null
}
// validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
if (attachmentIDs.isNotEmpty()) return true
@ -98,7 +95,7 @@ class VisibleMessage : Message() {
}
}
//Attachments
val attachments = attachmentIDs.mapNotNull { MessagingConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(it) }
val attachments = attachmentIDs.mapNotNull { MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(it) }
if (!attachments.all { !it.url.isNullOrEmpty() }) {
if (BuildConfig.DEBUG) {
//TODO equivalent to iOS's preconditionFailure
@ -111,8 +108,8 @@ class VisibleMessage : Message() {
// Expiration timer
// TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation
// if it receives a message without the current expiration timer value attached to it...
val storage = MessagingConfiguration.shared.storage
val context = MessagingConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val expiration = if (storage.isClosedGroup(recipient!!)) Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(recipient!!)), false).expireMessages
else Recipient.from(context, Address.fromSerialized(recipient!!), false).expireMessages
dataMessage.expireTimer = expiration

View File

@ -1,6 +1,5 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
import org.session.libsignal.service.loki.api.opengroups.PublicChat
import org.session.libsignal.utilities.JsonUtil
data class OpenGroup(
@ -14,9 +13,6 @@ data class OpenGroup(
companion object {
@JvmStatic fun from(publicChat: PublicChat): OpenGroup =
OpenGroup(publicChat.channel, publicChat.server, publicChat.displayName, publicChat.isDeletable)
@JvmStatic fun getId(channel: Long, server: String): String {
return "$server.$channel"
}

View File

@ -1,19 +1,20 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
import nl.komponents.kovenant.Kovenant
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import nl.komponents.kovenant.functional.map
import nl.komponents.kovenant.then
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.fileserver.FileServerAPI
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.file_server.FileServerAPI
import org.session.libsession.messaging.utilities.DotNetAPI
import org.session.libsignal.service.loki.utilities.DownloadUtilities
import org.session.libsession.utilities.DownloadUtilities
import org.session.libsignal.service.loki.utilities.retryIfNeeded
import org.session.libsignal.utilities.*
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.logging.Log
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
@ -51,7 +52,7 @@ object OpenGroupAPI: DotNetAPI() {
// region Public API
fun getMessages(channel: Long, server: String): Promise<List<OpenGroupMessage>, Exception> {
Log.d("Loki", "Getting messages for open group with ID: $channel on server: $server.")
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val parameters = mutableMapOf<String, Any>( "include_annotations" to 1 )
val lastMessageServerID = storage.getLastMessageServerID(channel, server)
if (lastMessageServerID != null) {
@ -157,7 +158,7 @@ object OpenGroupAPI: DotNetAPI() {
@JvmStatic
fun getDeletedMessageServerIDs(channel: Long, server: String): Promise<List<Long>, Exception> {
Log.d("Loki", "Getting deleted messages for open group with ID: $channel on server: $server.")
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val parameters = mutableMapOf<String, Any>()
val lastDeletionServerID = storage.getLastDeletionServerID(channel, server)
if (lastDeletionServerID != null) {
@ -190,7 +191,7 @@ object OpenGroupAPI: DotNetAPI() {
@JvmStatic
fun sendMessage(message: OpenGroupMessage, channel: Long, server: String): Promise<OpenGroupMessage, Exception> {
val deferred = deferred<OpenGroupMessage, Exception>()
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userKeyPair = storage.getUserKeyPair() ?: throw Error.Generic
val userDisplayName = storage.getUserDisplayName() ?: throw Error.Generic
ThreadUtils.queue {
@ -286,7 +287,7 @@ object OpenGroupAPI: DotNetAPI() {
val memberCount = countInfo["subscribers"] as? Int ?: (countInfo["subscribers"] as? Long)?.toInt() ?: (countInfo["subscribers"] as String).toInt()
val profilePictureURL = info["avatar"] as String
val publicChatInfo = OpenGroupInfo(displayName, profilePictureURL, memberCount)
MessagingConfiguration.shared.storage.setUserCount(channel, server, memberCount)
MessagingModuleConfiguration.shared.storage.setUserCount(channel, server, memberCount)
publicChatInfo
} catch (exception: Exception) {
Log.d("Loki", "Couldn't parse info for open group with ID: $channel on server: $server.")
@ -298,7 +299,7 @@ object OpenGroupAPI: DotNetAPI() {
@JvmStatic
fun updateProfileIfNeeded(channel: Long, server: String, groupID: String, info: OpenGroupInfo, isForcedUpdate: Boolean) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
storage.setUserCount(channel, server, info.memberCount)
storage.updateTitle(groupID, info.displayName)
// Download and update profile picture if needed

View File

@ -1,10 +1,9 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.databind.annotation.JsonNaming
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import nl.komponents.kovenant.Kovenant
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind
@ -13,14 +12,12 @@ import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.RequestBody
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.fileserver.FileServerAPI
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2.Error
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2.Error
import org.session.libsession.snode.OnionRequestAPI
import org.session.libsession.utilities.AESGCM
import org.session.libsignal.service.loki.api.utilities.HTTP
import org.session.libsignal.service.loki.api.utilities.HTTP.Verb.*
import org.session.libsignal.service.loki.utilities.DownloadUtilities
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
import org.session.libsignal.service.loki.utilities.toHexString
import org.session.libsignal.utilities.Base64.*
@ -29,7 +26,6 @@ import org.session.libsignal.utilities.JsonUtil
import org.session.libsignal.utilities.createContext
import org.session.libsignal.utilities.logging.Log
import org.whispersystems.curve25519.Curve25519
import java.io.ByteArrayOutputStream
import java.util.*
object OpenGroupAPIV2 {
@ -130,12 +126,12 @@ object OpenGroupAPIV2 {
}
if (request.useOnionRouting) {
val publicKey = MessagingConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
val publicKey = MessagingModuleConfiguration.shared.storage.getOpenGroupPublicKey(request.server)
?: return Promise.ofFail(Error.NO_PUBLIC_KEY)
return OnionRequestAPI.sendOnionRequest(requestBuilder.build(), request.server, publicKey)
.fail { e ->
if (e is OnionRequestAPI.HTTPRequestFailedAtDestinationException && e.statusCode == 401) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
if (request.room != null) {
storage.removeAuthToken("${request.server}.${request.room}")
} else {
@ -163,7 +159,7 @@ object OpenGroupAPIV2 {
}
fun getAuthToken(room: String, server: String): Promise<String, Exception> {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
return storage.getAuthToken(room, server)?.let {
Promise.of(it)
} ?: run {
@ -176,7 +172,7 @@ object OpenGroupAPIV2 {
}
fun requestNewAuthToken(room: String, server: String): Promise<String, Exception> {
val (publicKey, privateKey) = MessagingConfiguration.shared.storage.getUserKeyPair()
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserKeyPair()
?: return Promise.ofFail(Error.GENERIC)
val queryParameters = mutableMapOf("public_key" to publicKey)
val request = Request(GET, room, server, "auth_token_challenge", queryParameters, isAuthRequired = false, parameters = null)
@ -199,7 +195,7 @@ object OpenGroupAPIV2 {
}
fun claimAuthToken(authToken: String, room: String, server: String): Promise<String, Exception> {
val parameters = mapOf("public_key" to MessagingConfiguration.shared.storage.getUserPublicKey()!!)
val parameters = mapOf("public_key" to MessagingModuleConfiguration.shared.storage.getUserPublicKey()!!)
val headers = mapOf("Authorization" to authToken)
val request = Request(verb = POST, room = room, server = server, endpoint = "claim_auth_token",
parameters = parameters, headers = headers, isAuthRequired = false)
@ -209,7 +205,7 @@ object OpenGroupAPIV2 {
fun deleteAuthToken(room: String, server: String): Promise<Unit, Exception> {
val request = Request(verb = DELETE, room = room, server = server, endpoint = "auth_token")
return send(request).map(sharedContext) {
MessagingConfiguration.shared.storage.removeAuthToken(room, server)
MessagingModuleConfiguration.shared.storage.removeAuthToken(room, server)
}
}
@ -245,7 +241,7 @@ object OpenGroupAPIV2 {
// region Messages
fun getMessages(room: String, server: String): Promise<List<OpenGroupMessageV2>, Exception> {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val queryParameters = mutableMapOf<String, String>()
storage.getLastMessageServerId(room, server)?.let { lastId ->
queryParameters += "from_server_id" to lastId.toString()
@ -294,7 +290,7 @@ object OpenGroupAPIV2 {
}
fun getDeletedMessages(room: String, server: String): Promise<List<Long>, Exception> {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val queryParameters = mutableMapOf<String, String>()
storage.getLastDeletionServerId(room, server)?.let { last ->
queryParameters["from_server_id"] = last.toString()
@ -347,15 +343,33 @@ object OpenGroupAPIV2 {
// endregion
// region General
// fun getCompactPoll(rooms: List<String>, server: String): Promise<Map<String,CompactPollResult>, Exception> {
// val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false)
//
// // build a request for all rooms
//
// }
fun getCompactPoll(rooms: List<String>, server: String): Promise<Map<String,CompactPollResult>, Exception> {
val requestAuths = rooms.associateWith { room -> getAuthToken(room,server) }
val storage = MessagingModuleConfiguration.shared.storage
val requests = rooms.mapNotNull { room ->
val authToken = try {
requestAuths[room]?.get()
} catch (e: Exception) {
Log.e("Loki", "Failed to get auth token for $room",e)
null
} ?: return@mapNotNull null
CompactPollRequest(roomId = room,
authToken = authToken,
fromDeletionServerId = storage.getLastDeletionServerId(room, server),
fromMessageServerId = storage.getLastMessageServerId(room, server)
)
}
val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false, parameters = mapOf("requests" to requests))
// build a request for all rooms
return send(request = request).map(sharedContext) { json ->
val results = json["results"] as? Map<*,*> ?: throw Error.PARSING_FAILED
TODO()
}
}
fun getDefaultRoomsIfNeeded(): Promise<List<DefaultGroup>, Exception> {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
storage.setOpenGroupPublicKey(DEFAULT_SERVER, DEFAULT_SERVER_PUBLIC_KEY)
return getAllRooms(DEFAULT_SERVER).map { groups ->
val earlyGroups = groups.map { group ->
@ -414,7 +428,7 @@ object OpenGroupAPIV2 {
val request = Request(verb = GET, room = room, server = server, endpoint = "member_count")
return send(request).map(sharedContext) { json ->
val memberCount = json["member_count"] as? Long ?: throw Error.PARSING_FAILED
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
storage.setUserCount(room, server, memberCount)
memberCount
}

View File

@ -1,4 +1,4 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
data class OpenGroupInfo (
val displayName: String,

View File

@ -1,6 +1,6 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
import org.session.libsignal.utilities.Hex
@ -24,7 +24,7 @@ data class OpenGroupMessage(
// region Settings
companion object {
fun from(message: VisibleMessage, server: String): OpenGroupMessage? {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey() ?: return null
val attachmentIDs = message.attachmentIDs
// Validation
@ -50,7 +50,7 @@ data class OpenGroupMessage(
linkPreview?.let {
if (!linkPreview.isValid()) { return@let }
val attachmentID = linkPreview.attachmentID ?: return@let
val attachment = MessagingConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID) ?: return@let
val attachment = MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID) ?: return@let
val openGroupLinkPreview = Attachment(
Attachment.Kind.LinkPreview,
server,
@ -69,7 +69,7 @@ data class OpenGroupMessage(
}
// Attachments
val attachments = message.attachmentIDs.mapNotNull {
val attachment = MessagingConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(it) ?: return@mapNotNull null
val attachment = MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(it) ?: return@mapNotNull null
return@mapNotNull Attachment(
Attachment.Kind.Attachment,
server,

View File

@ -1,6 +1,6 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsignal.service.internal.push.PushTransportDetails
import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.utilities.Base64
@ -40,7 +40,7 @@ data class OpenGroupMessageV2(
fun sign(): OpenGroupMessageV2? {
if (base64EncodedData.isEmpty()) return null
val (publicKey, privateKey) = MessagingConfiguration.shared.storage.getUserKeyPair() ?: return null
val (publicKey, privateKey) = MessagingModuleConfiguration.shared.storage.getUserKeyPair() ?: return null
if (sender != publicKey) return null // only sign our own messages?

View File

@ -1,4 +1,4 @@
package org.session.libsession.messaging.opengroups
package org.session.libsession.messaging.open_groups
import org.session.libsignal.utilities.JsonUtil
import java.util.*

View File

@ -1,6 +1,6 @@
package org.session.libsession.messaging.sending_receiving
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.control.*
import org.session.libsession.messaging.messages.visible.VisibleMessage
@ -44,7 +44,7 @@ object MessageReceiver {
}
internal fun parse(data: ByteArray, openGroupServerID: Long?, isRetry: Boolean = false): Pair<Message, SignalServiceProtos.Content> {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()
val isOpenGroupMessage = openGroupServerID != null
// Parse the envelope
@ -63,18 +63,18 @@ object MessageReceiver {
sender = envelope.source
} else {
when (envelope.type) {
SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER -> {
val userX25519KeyPair = MessagingConfiguration.shared.storage.getUserX25519KeyPair()
SignalServiceProtos.Envelope.Type.SESSION_MESSAGE -> {
val userX25519KeyPair = MessagingModuleConfiguration.shared.storage.getUserX25519KeyPair()
val decryptionResult = MessageReceiverDecryption.decryptWithSessionProtocol(ciphertext.toByteArray(), userX25519KeyPair)
plaintext = decryptionResult.first
sender = decryptionResult.second
}
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_CIPHERTEXT -> {
SignalServiceProtos.Envelope.Type.CLOSED_GROUP_MESSAGE -> {
val hexEncodedGroupPublicKey = envelope.source
if (hexEncodedGroupPublicKey == null || !MessagingConfiguration.shared.storage.isClosedGroup(hexEncodedGroupPublicKey)) {
if (hexEncodedGroupPublicKey == null || !MessagingModuleConfiguration.shared.storage.isClosedGroup(hexEncodedGroupPublicKey)) {
throw Error.InvalidGroupPublicKey
}
val encryptionKeyPairs = MessagingConfiguration.shared.storage.getClosedGroupEncryptionKeyPairs(hexEncodedGroupPublicKey)
val encryptionKeyPairs = MessagingModuleConfiguration.shared.storage.getClosedGroupEncryptionKeyPairs(hexEncodedGroupPublicKey)
if (encryptionKeyPairs.isEmpty()) { throw Error.NoGroupKeyPair }
// Loop through all known group key pairs in reverse order (i.e. try the latest key pair first (which'll more than
// likely be the one we want) but try older ones in case that didn't work)
@ -107,12 +107,12 @@ object MessageReceiver {
val proto = SignalServiceProtos.Content.parseFrom(PushTransportDetails.getStrippedPaddingMessageBody(plaintext))
// Parse the message
val message: Message = ReadReceipt.fromProto(proto) ?:
TypingIndicator.fromProto(proto) ?:
ClosedGroupControlMessage.fromProto(proto) ?:
DataExtractionNotification.fromProto(proto) ?:
ExpirationTimerUpdate.fromProto(proto) ?:
ConfigurationMessage.fromProto(proto) ?:
VisibleMessage.fromProto(proto) ?: throw Error.UnknownMessage
TypingIndicator.fromProto(proto) ?:
ClosedGroupControlMessage.fromProto(proto) ?:
DataExtractionNotification.fromProto(proto) ?:
ExpirationTimerUpdate.fromProto(proto) ?:
ConfigurationMessage.fromProto(proto) ?:
VisibleMessage.fromProto(proto) ?: throw Error.UnknownMessage
// Ignore self sends if needed
if (!message.isSelfSendValid && sender == userPublicKey) throw Error.SelfSend
// Guard against control messages in open groups

View File

@ -1,11 +1,11 @@
package org.session.libsession.messaging.sending_receiving
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsignal.libsignal.ecc.ECKeyPair
object MessageReceiverDecryption {
internal fun decryptWithSessionProtocol(ciphertext: ByteArray, x25519KeyPair: ECKeyPair): Pair<ByteArray, String> {
return MessagingConfiguration.shared.sessionProtocol.decrypt(ciphertext, x25519KeyPair)
return MessagingModuleConfiguration.shared.sessionProtocol.decrypt(ciphertext, x25519KeyPair)
}
}

View File

@ -2,7 +2,7 @@ package org.session.libsession.messaging.sending_receiving
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageSendJob
import org.session.libsession.messaging.jobs.NotifyPNServerJob
@ -12,15 +12,15 @@ import org.session.libsession.messaging.messages.control.ClosedGroupControlMessa
import org.session.libsession.messaging.messages.control.ConfigurationMessage
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
import org.session.libsession.messaging.messages.visible.*
import org.session.libsession.messaging.opengroups.OpenGroupAPI
import org.session.libsession.messaging.opengroups.OpenGroupAPIV2
import org.session.libsession.messaging.opengroups.OpenGroupMessage
import org.session.libsession.messaging.opengroups.OpenGroupMessageV2
import org.session.libsession.messaging.open_groups.OpenGroupAPI
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
import org.session.libsession.messaging.open_groups.OpenGroupMessage
import org.session.libsession.messaging.open_groups.OpenGroupMessageV2
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.snode.RawResponsePromise
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.snode.SnodeConfiguration
import org.session.libsession.snode.SnodeModule
import org.session.libsession.snode.SnodeMessage
import org.session.libsession.utilities.SSKEnvironment
import org.session.libsignal.service.internal.push.PushTransportDetails
@ -29,10 +29,9 @@ import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.logging.Log
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview as SignalLinkPreview
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview as SignalLinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel as SignalQuote
object MessageSender {
// Error
@ -75,7 +74,7 @@ object MessageSender {
private fun sendToSnodeDestination(destination: Destination, message: Message, isSyncMessage: Boolean = false): Promise<Unit, Exception> {
val deferred = deferred<Unit, Exception>()
val promise = deferred.promise
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()
// Set the timestamp, sender and recipient
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() } /* Visible messages will already have their sent timestamp set */
@ -85,7 +84,7 @@ object MessageSender {
fun handleFailure(error: Exception) {
handleFailedMessageSend(message, error)
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
SnodeConfiguration.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!)
SnodeModule.shared.broadcaster.broadcast("messageFailed", message.sentTimestamp!!)
}
deferred.reject(error)
}
@ -129,7 +128,7 @@ object MessageSender {
when (destination) {
is Destination.Contact -> ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, destination.publicKey)
is Destination.ClosedGroup -> {
val encryptionKeyPair = MessagingConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(destination.groupPublicKey)!!
val encryptionKeyPair = MessagingModuleConfiguration.shared.storage.getLatestClosedGroupEncryptionKeyPair(destination.groupPublicKey)!!
ciphertext = MessageSenderEncryption.encryptWithSessionProtocol(plaintext, encryptionKeyPair.hexEncodedPublicKey)
}
is Destination.OpenGroup,
@ -140,27 +139,26 @@ object MessageSender {
val senderPublicKey: String
when (destination) {
is Destination.Contact -> {
kind = SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER
kind = SignalServiceProtos.Envelope.Type.SESSION_MESSAGE
senderPublicKey = ""
}
is Destination.ClosedGroup -> {
kind = SignalServiceProtos.Envelope.Type.CLOSED_GROUP_CIPHERTEXT
kind = SignalServiceProtos.Envelope.Type.CLOSED_GROUP_MESSAGE
senderPublicKey = destination.groupPublicKey
}
is Destination.OpenGroup,
is Destination.OpenGroupV2 -> throw Error.PreconditionFailure("Destination should not be open groups!")
}
val wrappedMessage = MessageWrapper.wrap(kind, message.sentTimestamp!!, senderPublicKey, ciphertext)
// Calculate proof of work
// Send the result
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
SnodeConfiguration.shared.broadcaster.broadcast("calculatingPoW", message.sentTimestamp!!)
SnodeModule.shared.broadcaster.broadcast("calculatingPoW", message.sentTimestamp!!)
}
val recipient = message.recipient!!
val base64EncodedData = Base64.encodeBytes(wrappedMessage)
// Send the result
val snodeMessage = SnodeMessage(recipient, base64EncodedData, message.ttl, message.sentTimestamp!!)
val snodeMessage = SnodeMessage(message.recipient!!, base64EncodedData, message.ttl, message.sentTimestamp!!)
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
SnodeConfiguration.shared.broadcaster.broadcast("sendingMessage", message.sentTimestamp!!)
SnodeModule.shared.broadcaster.broadcast("sendingMessage", message.sentTimestamp!!)
}
SnodeAPI.sendMessage(snodeMessage).success { promises: Set<RawResponsePromise> ->
var isSuccess = false
@ -171,7 +169,7 @@ object MessageSender {
if (isSuccess) { return@success } // Succeed as soon as the first promise succeeds
isSuccess = true
if (destination is Destination.Contact && message is VisibleMessage && !isSelfSend) {
SnodeConfiguration.shared.broadcaster.broadcast("messageSent", message.sentTimestamp!!)
SnodeModule.shared.broadcaster.broadcast("messageSent", message.sentTimestamp!!)
}
handleSuccessfulMessageSend(message, destination, isSyncMessage)
var shouldNotify = (message is VisibleMessage && !isSyncMessage)
@ -203,7 +201,7 @@ object MessageSender {
// Open Groups
private fun sendToOpenGroupDestination(destination: Destination, message: Message): Promise<Unit, Exception> {
val deferred = deferred<Unit, Exception>()
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
message.sentTimestamp ?: run { message.sentTimestamp = System.currentTimeMillis() }
message.sender = storage.getUserPublicKey()
// Set the failure handler (need it here already for precondition failure handling)
@ -286,7 +284,7 @@ object MessageSender {
// Result Handling
fun handleSuccessfulMessageSend(message: Message, destination: Destination, isSyncMessage: Boolean = false) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
val messageId = storage.getMessageIdInDatabase(message.sentTimestamp!!, message.sender?:userPublicKey) ?: return
// Ignore future self-sends
@ -314,7 +312,7 @@ object MessageSender {
}
fun handleFailedMessageSend(message: Message, error: Exception) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
storage.setErrorMessage(message.sentTimestamp!!, message.sender?:userPublicKey, error)
}
@ -322,7 +320,7 @@ object MessageSender {
// Convenience
@JvmStatic
fun send(message: VisibleMessage, address: Address, attachments: List<SignalAttachment>, quote: SignalQuote?, linkPreview: SignalLinkPreview?) {
val dataProvider = MessagingConfiguration.shared.messageDataProvider
val dataProvider = MessagingModuleConfiguration.shared.messageDataProvider
val attachmentIDs = dataProvider.getAttachmentIDsFor(message.id!!)
message.attachmentIDs.addAll(attachmentIDs)
message.quote = Quote.from(quote)
@ -340,7 +338,7 @@ object MessageSender {
@JvmStatic
fun send(message: Message, address: Address) {
val threadID = MessagingConfiguration.shared.storage.getOrCreateThreadIdFor(address)
val threadID = MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(address)
message.threadID = threadID
val destination = Destination.from(address)
val job = MessageSendJob(message, destination)
@ -348,13 +346,13 @@ object MessageSender {
}
fun sendNonDurably(message: VisibleMessage, attachments: List<SignalAttachment>, address: Address): Promise<Unit, Exception> {
val attachmentIDs = MessagingConfiguration.shared.messageDataProvider.getAttachmentIDsFor(message.id!!)
val attachmentIDs = MessagingModuleConfiguration.shared.messageDataProvider.getAttachmentIDsFor(message.id!!)
message.attachmentIDs.addAll(attachmentIDs)
return sendNonDurably(message, address)
}
fun sendNonDurably(message: Message, address: Address): Promise<Unit, Exception> {
val threadID = MessagingConfiguration.shared.storage.getOrCreateThreadIdFor(address)
val threadID = MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(address)
message.threadID = threadID
val destination = Destination.from(address)
return send(message, destination)

View File

@ -5,7 +5,7 @@ package org.session.libsession.messaging.sending_receiving
import com.google.protobuf.ByteString
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
@ -32,8 +32,8 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
val deferred = deferred<String, Exception>()
ThreadUtils.queue {
// Prepare
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
val membersAsData = members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }
// Generate the group's public key
@ -72,8 +72,8 @@ fun MessageSender.create(name: String, members: Collection<String>): Promise<Str
}
fun MessageSender.update(groupPublicKey: String, members: List<String>, name: String) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Can't update nonexistent closed group.")
@ -90,8 +90,8 @@ fun MessageSender.update(groupPublicKey: String, members: List<String>, name: St
}
fun MessageSender.setName(groupPublicKey: String, newName: String) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Can't change name for nonexistent closed group.")
@ -114,8 +114,8 @@ fun MessageSender.setName(groupPublicKey: String, newName: String) {
}
fun MessageSender.addMembers(groupPublicKey: String, membersToAdd: List<String>) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Can't add members to nonexistent closed group.")
@ -157,8 +157,8 @@ fun MessageSender.addMembers(groupPublicKey: String, membersToAdd: List<String>)
}
fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List<String>) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
@ -198,8 +198,8 @@ fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List<St
fun MessageSender.leave(groupPublicKey: String, notifyUser: Boolean = true): Promise<Unit, Exception> {
val deferred = deferred<Unit, Exception>()
ThreadUtils.queue {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: return@queue deferred.reject(Error.NoThread)
@ -230,7 +230,7 @@ fun MessageSender.leave(groupPublicKey: String, notifyUser: Boolean = true): Pro
fun MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey: String, targetMembers: Collection<String>) {
// Prepare
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
@ -278,25 +278,8 @@ fun MessageSender.sendEncryptionKeyPair(groupPublicKey: String, newKeyPair: ECKe
}
}
/// Note: Shouldn't currently be in use.
fun MessageSender.requestEncryptionKeyPair(groupPublicKey: String) {
val storage = MessagingConfiguration.shared.storage
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Can't request encryption key pair for nonexistent closed group.")
throw Error.NoThread
}
val members = group.members.map { it.serialize() }.toSet()
if (!members.contains(storage.getUserPublicKey()!!)) return
// Send the request to the group
val sentTime = System.currentTimeMillis()
val closedGroupControlMessage = ClosedGroupControlMessage(ClosedGroupControlMessage.Kind.EncryptionKeyPairRequest())
closedGroupControlMessage.sentTimestamp = sentTime
send(closedGroupControlMessage, Address.fromSerialized(groupID))
}
fun MessageSender.sendLatestEncryptionKeyPair(publicKey: String, groupPublicKey: String) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Can't send encryption key pair for nonexistent closed group.")

View File

@ -5,7 +5,7 @@ import com.goterl.lazycode.lazysodium.SodiumAndroid
import com.goterl.lazycode.lazysodium.interfaces.Box
import com.goterl.lazycode.lazysodium.interfaces.Sign
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
import org.session.libsession.utilities.KeyPairUtilities
@ -26,7 +26,7 @@ object MessageSenderEncryption {
* @return the encrypted message.
*/
internal fun encryptWithSessionProtocol(plaintext: ByteArray, recipientHexEncodedX25519PublicKey: String): ByteArray{
val context = MessagingConfiguration.shared.context
val context = MessagingModuleConfiguration.shared.context
val userED25519KeyPair = KeyPairUtilities.getUserED25519KeyPair(context) ?: throw Error.NoUserED25519KeyPair
val recipientX25519PublicKey = Hex.fromStringCondensed(recipientHexEncodedX25519PublicKey.removing05PrefixIfNeeded())

View File

@ -1,7 +1,7 @@
package org.session.libsession.messaging.sending_receiving
import android.text.TextUtils
import org.session.libsession.messaging.MessagingConfiguration
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.messages.Message
@ -9,8 +9,8 @@ import org.session.libsession.messaging.messages.control.*
import org.session.libsession.messaging.messages.visible.Attachment
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment
import org.session.libsession.messaging.sending_receiving.dataextraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationAPI
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.messaging.threads.Address
@ -35,7 +35,7 @@ import java.util.*
import kotlin.collections.ArrayList
internal fun MessageReceiver.isBlock(publicKey: String): Boolean {
val context = MessagingConfiguration.shared.context
val context = MessagingModuleConfiguration.shared.context
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
return recipient.isBlocked
}
@ -53,7 +53,7 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content,
}
private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) {
val context = MessagingConfiguration.shared.context
val context = MessagingModuleConfiguration.shared.context
SSKEnvironment.shared.readReceiptManager.processReadReceipts(context, message.sender!!, message.timestamps!!, message.receivedTimestamp!!)
}
@ -65,23 +65,23 @@ private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) {
}
fun MessageReceiver.showTypingIndicatorIfNeeded(senderPublicKey: String) {
val context = MessagingConfiguration.shared.context
val context = MessagingModuleConfiguration.shared.context
val address = Address.fromSerialized(senderPublicKey)
val threadID = MessagingConfiguration.shared.storage.getThreadIdFor(address) ?: return
val threadID = MessagingModuleConfiguration.shared.storage.getThreadIdFor(address) ?: return
SSKEnvironment.shared.typingIndicators.didReceiveTypingStartedMessage(context, threadID, address, 1)
}
fun MessageReceiver.hideTypingIndicatorIfNeeded(senderPublicKey: String) {
val context = MessagingConfiguration.shared.context
val context = MessagingModuleConfiguration.shared.context
val address = Address.fromSerialized(senderPublicKey)
val threadID = MessagingConfiguration.shared.storage.getThreadIdFor(address) ?: return
val threadID = MessagingModuleConfiguration.shared.storage.getThreadIdFor(address) ?: return
SSKEnvironment.shared.typingIndicators.didReceiveTypingStoppedMessage(context, threadID, address, 1, false)
}
fun MessageReceiver.cancelTypingIndicatorsIfNeeded(senderPublicKey: String) {
val context = MessagingConfiguration.shared.context
val context = MessagingModuleConfiguration.shared.context
val address = Address.fromSerialized(senderPublicKey)
val threadID = MessagingConfiguration.shared.storage.getThreadIdFor(address) ?: return
val threadID = MessagingModuleConfiguration.shared.storage.getThreadIdFor(address) ?: return
SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(context, threadID, address, 1)
}
@ -99,7 +99,7 @@ private fun MessageReceiver.handleDataExtractionNotification(message: DataExtrac
// we don't handle data extraction messages for groups (they shouldn't be sent, but in case we filter them here too)
if (message.groupPublicKey != null) return
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val senderPublicKey = message.sender!!
val notification: DataExtractionNotificationInfoMessage = when(message.kind) {
is DataExtractionNotification.Kind.Screenshot -> DataExtractionNotificationInfoMessage(DataExtractionNotificationInfoMessage.Kind.SCREENSHOT)
@ -112,8 +112,8 @@ private fun MessageReceiver.handleDataExtractionNotification(message: DataExtrac
// Configuration message handling
private fun handleConfigurationMessage(message: ConfigurationMessage) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
if (TextSecurePreferences.getConfigurationMessageSynced(context) && !TextSecurePreferences.shouldUpdateProfile(context, message.sentTimestamp!!)) return
val userPublicKey = storage.getUserPublicKey()
if (userPublicKey == null || message.sender != storage.getUserPublicKey()) return
@ -148,8 +148,8 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) {
}
fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalServiceProtos.Content, openGroupID: String?) {
val storage = MessagingConfiguration.shared.storage
val context = MessagingConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val userPublicKey = storage.getUserPublicKey()
// Update profile if needed
val newProfile = message.profile
@ -180,10 +180,10 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
if (message.quote != null && proto.dataMessage.hasQuote()) {
val quote = proto.dataMessage.quote
val author = Address.fromSerialized(quote.author)
val messageInfo = MessagingConfiguration.shared.messageDataProvider.getMessageForQuote(quote.id, author)
val messageInfo = MessagingModuleConfiguration.shared.messageDataProvider.getMessageForQuote(quote.id, author)
if (messageInfo != null) {
val attachments = if (messageInfo.second) MessagingConfiguration.shared.messageDataProvider.getAttachmentsAndLinkPreviewFor(messageInfo.first) else ArrayList()
quoteModel = QuoteModel(quote.id, author, MessagingConfiguration.shared.messageDataProvider.getMessageBodyFor(quote.id, quote.author), false, attachments)
val attachments = if (messageInfo.second) MessagingModuleConfiguration.shared.messageDataProvider.getAttachmentsAndLinkPreviewFor(messageInfo.first) else ArrayList()
quoteModel = QuoteModel(quote.id, author, MessagingModuleConfiguration.shared.messageDataProvider.getMessageBodyFor(quote.id, quote.author), false, attachments)
} else {
quoteModel = QuoteModel(quote.id, author, quote.text, true, PointerAttachment.forPointers(proto.dataMessage.quote.attachmentsList))
}
@ -233,13 +233,11 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
private fun MessageReceiver.handleClosedGroupControlMessage(message: ClosedGroupControlMessage) {
when (message.kind!!) {
is ClosedGroupControlMessage.Kind.New -> handleNewClosedGroup(message)
is ClosedGroupControlMessage.Kind.Update -> handleClosedGroupUpdated(message)
is ClosedGroupControlMessage.Kind.EncryptionKeyPair -> handleClosedGroupEncryptionKeyPair(message)
is ClosedGroupControlMessage.Kind.NameChange -> handleClosedGroupNameChanged(message)
is ClosedGroupControlMessage.Kind.MembersAdded -> handleClosedGroupMembersAdded(message)
is ClosedGroupControlMessage.Kind.MembersRemoved -> handleClosedGroupMembersRemoved(message)
is ClosedGroupControlMessage.Kind.MemberLeft -> handleClosedGroupMemberLeft(message)
is ClosedGroupControlMessage.Kind.EncryptionKeyPairRequest -> handleClosedGroupEncryptionKeyPairRequest(message)
}
}
@ -253,8 +251,8 @@ private fun MessageReceiver.handleNewClosedGroup(message: ClosedGroupControlMess
// Parameter @sender:String is just for inserting incoming info message
private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPublicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: List<String>, admins: List<String>, formationTimestamp: Long) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
// Create the group
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
if (storage.getGroup(groupID) != null) {
@ -283,62 +281,9 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli
PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Subscribe, groupPublicKey, storage.getUserPublicKey()!!)
}
private fun MessageReceiver.handleClosedGroupUpdated(message: ClosedGroupControlMessage) {
// Prepare
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val senderPublicKey = message.sender ?: return
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.Update ?: return
val groupPublicKey = message.groupPublicKey ?: return
val userPublicKey = storage.getUserPublicKey()!!
// Unwrap the message
val name = kind.name
val members = kind.members.map { it.toByteArray().toHexString() }
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
return
}
if (!group.isActive) {
Log.d("Loki", "Ignoring closed group info message for inactive group")
return
}
val oldMembers = group.members.map { it.serialize() }
// Check common group update logic
if (!isValidGroupUpdate(group, message.sentTimestamp!!, senderPublicKey)) {
return
}
// Check that the admin wasn't removed unless the group was destroyed entirely
if (!members.contains(group.admins.first().toString()) && members.isNotEmpty()) {
android.util.Log.d("Loki", "Ignoring invalid closed group update message.")
return
}
// Remove the group from the user's set of public keys to poll for if the current user was removed
val wasCurrentUserRemoved = !members.contains(userPublicKey)
if (wasCurrentUserRemoved) {
disableLocalGroupAndUnsubscribe(groupPublicKey, groupID, userPublicKey)
}
// Generate and distribute a new encryption key pair if needed
val wasAnyUserRemoved = (members.toSet().intersect(oldMembers) != oldMembers.toSet())
val isCurrentUserAdmin = group.admins.map { it.toString() }.contains(userPublicKey)
if (wasAnyUserRemoved && isCurrentUserAdmin) {
MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, members)
}
// Update the group
storage.updateTitle(groupID, name)
if (!wasCurrentUserRemoved) {
// The call below sets isActive to true, so if the user is leaving we have to use groupDB.remove(...) instead
storage.updateMembers(groupID, members.map { Address.fromSerialized(it) })
}
// Notify the user
val wasSenderRemoved = !members.contains(senderPublicKey)
val type = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.MEMBER_REMOVED
storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, group.admins.map { it.toString() }, message.sentTimestamp!!)
}
private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGroupControlMessage) {
// Prepare
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
val senderPublicKey = message.sender ?: return
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.EncryptionKeyPair ?: return
val groupPublicKey = kind.publicKey?.toByteArray()?.toHexString() ?: message.groupPublicKey ?: return
@ -376,8 +321,8 @@ private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGr
}
private fun MessageReceiver.handleClosedGroupNameChanged(message: ClosedGroupControlMessage) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
val senderPublicKey = message.sender ?: return
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.NameChange ?: return
@ -412,8 +357,8 @@ private fun MessageReceiver.handleClosedGroupNameChanged(message: ClosedGroupCon
}
private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupControlMessage) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
val senderPublicKey = message.sender ?: return
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.MembersAdded ?: return
@ -459,8 +404,8 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo
}
private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroupControlMessage) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val userPublicKey = storage.getUserPublicKey()!!
val senderPublicKey = message.sender ?: return
val kind = message.kind!! as? ClosedGroupControlMessage.Kind.MembersRemoved ?: return
@ -518,8 +463,8 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup
}
private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupControlMessage) {
val context = MessagingConfiguration.shared.context
val storage = MessagingConfiguration.shared.storage
val context = MessagingModuleConfiguration.shared.context
val storage = MessagingModuleConfiguration.shared.storage
val senderPublicKey = message.sender ?: return
val userPublicKey = storage.getUserPublicKey()!!
if (message.kind!! !is ClosedGroupControlMessage.Kind.MemberLeft) return
@ -565,31 +510,6 @@ private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupCont
}
}
private fun MessageReceiver.handleClosedGroupEncryptionKeyPairRequest(message: ClosedGroupControlMessage) {
val storage = MessagingConfiguration.shared.storage
val senderPublicKey = message.sender ?: return
val userPublicKey = storage.getUserPublicKey()!!
if (message.kind!! !is ClosedGroupControlMessage.Kind.EncryptionKeyPairRequest) return
if (senderPublicKey == userPublicKey) {
Log.d("Loki", "Ignoring invalid closed group update.")
return
}
val groupPublicKey = message.groupPublicKey ?: return
val groupID = GroupUtil.doubleEncodeGroupID(groupPublicKey)
val group = storage.getGroup(groupID) ?: run {
Log.d("Loki", "Ignoring closed group info message for nonexistent group.")
return
}
if (!isValidGroupUpdate(group, message.sentTimestamp!!, senderPublicKey)) { return }
val encryptionKeyPair = pendingKeyPair[groupPublicKey]?.orNull()
?: storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
if (encryptionKeyPair == null) {
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
} else {
MessageSender.sendEncryptionKeyPair(groupPublicKey, encryptionKeyPair, setOf(senderPublicKey), targetUser = senderPublicKey, force = false)
}
}
private fun isValidGroupUpdate(group: GroupRecord,
sentTimestamp: Long,
senderPublicKey: String): Boolean {
@ -608,7 +528,7 @@ private fun isValidGroupUpdate(group: GroupRecord,
}
fun MessageReceiver.disableLocalGroupAndUnsubscribe(groupPublicKey: String, groupID: String, userPublicKey: String) {
val storage = MessagingConfiguration.shared.storage
val storage = MessagingModuleConfiguration.shared.storage
storage.removeClosedGroupPublicKey(groupPublicKey)
// Remove the key pairs
storage.removeAllClosedGroupEncryptionKeyPairs(groupPublicKey)

View File

@ -4,7 +4,7 @@ import android.net.Uri;
import androidx.annotation.Nullable;
import org.session.libsession.messaging.MessagingConfiguration;
import org.session.libsession.messaging.MessagingModuleConfiguration;
public class DatabaseAttachment extends Attachment {
@ -33,7 +33,7 @@ public class DatabaseAttachment extends Attachment {
@Nullable
public Uri getDataUri() {
if (hasData) {
return MessagingConfiguration.shared.getStorage().getAttachmentDataUri(attachmentId);
return MessagingModuleConfiguration.shared.getStorage().getAttachmentDataUri(attachmentId);
} else {
return null;
}
@ -43,7 +43,7 @@ public class DatabaseAttachment extends Attachment {
@Nullable
public Uri getThumbnailUri() {
if (hasThumbnail) {
return MessagingConfiguration.shared.getStorage().getAttachmentThumbnailUri(attachmentId);
return MessagingModuleConfiguration.shared.getStorage().getAttachmentThumbnailUri(attachmentId);
} else {
return null;
}

View File

@ -1,4 +1,4 @@
package org.session.libsession.messaging.sending_receiving.dataextraction
package org.session.libsession.messaging.sending_receiving.data_extraction
class DataExtractionNotificationInfoMessage {

View File

@ -1,4 +1,4 @@
package org.session.libsession.messaging.sending_receiving.linkpreview;
package org.session.libsession.messaging.sending_receiving.link_preview;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

Some files were not shown because too many files have changed in this diff Show More