kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add report spam in message request state.
rodzic
c47dcd5720
commit
ef5b68eb35
|
@ -9,6 +9,8 @@ import androidx.annotation.WorkerThread;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
|
@ -30,15 +32,15 @@ public final class BlockUnblockDialog {
|
||||||
AlertDialog.Builder::show);
|
AlertDialog.Builder::show);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showBlockAndDeleteFor(@NonNull Context context,
|
public static void showBlockAndReportSpamFor(@NonNull Context context,
|
||||||
@NonNull Lifecycle lifecycle,
|
@NonNull Lifecycle lifecycle,
|
||||||
@NonNull Recipient recipient,
|
@NonNull Recipient recipient,
|
||||||
@NonNull Runnable onBlock,
|
@NonNull Runnable onBlock,
|
||||||
@NonNull Runnable onBlockAndDelete)
|
@NonNull Runnable onBlockAndReportSpam)
|
||||||
{
|
{
|
||||||
SimpleTask.run(lifecycle,
|
SimpleTask.run(lifecycle,
|
||||||
() -> buildBlockFor(context, recipient, onBlock, onBlockAndDelete),
|
() -> buildBlockFor(context, recipient, onBlock, onBlockAndReportSpam),
|
||||||
AlertDialog.Builder::show);
|
AlertDialog.Builder::show);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showUnblockFor(@NonNull Context context,
|
public static void showUnblockFor(@NonNull Context context,
|
||||||
|
@ -55,11 +57,11 @@ public final class BlockUnblockDialog {
|
||||||
private static AlertDialog.Builder buildBlockFor(@NonNull Context context,
|
private static AlertDialog.Builder buildBlockFor(@NonNull Context context,
|
||||||
@NonNull Recipient recipient,
|
@NonNull Recipient recipient,
|
||||||
@NonNull Runnable onBlock,
|
@NonNull Runnable onBlock,
|
||||||
@Nullable Runnable onBlockAndDelete)
|
@Nullable Runnable onBlockAndReportSpam)
|
||||||
{
|
{
|
||||||
recipient = recipient.resolve();
|
recipient = recipient.resolve();
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
|
||||||
Resources resources = context.getResources();
|
Resources resources = context.getResources();
|
||||||
|
|
||||||
if (recipient.isGroup()) {
|
if (recipient.isGroup()) {
|
||||||
|
@ -78,10 +80,10 @@ public final class BlockUnblockDialog {
|
||||||
builder.setTitle(resources.getString(R.string.BlockUnblockDialog_block_s, recipient.getDisplayName(context)));
|
builder.setTitle(resources.getString(R.string.BlockUnblockDialog_block_s, recipient.getDisplayName(context)));
|
||||||
builder.setMessage(R.string.BlockUnblockDialog_blocked_people_wont_be_able_to_call_you_or_send_you_messages);
|
builder.setMessage(R.string.BlockUnblockDialog_blocked_people_wont_be_able_to_call_you_or_send_you_messages);
|
||||||
|
|
||||||
if (onBlockAndDelete != null) {
|
if (onBlockAndReportSpam != null) {
|
||||||
builder.setNeutralButton(android.R.string.cancel, null);
|
builder.setNeutralButton(android.R.string.cancel, null);
|
||||||
builder.setPositiveButton(R.string.BlockUnblockDialog_block_and_delete, (d, w) -> onBlockAndDelete.run());
|
builder.setNegativeButton(R.string.BlockUnblockDialog_report_spam_and_block, (d, w) -> onBlockAndReportSpam.run());
|
||||||
builder.setNegativeButton(R.string.BlockUnblockDialog_block, (d, w) -> onBlock.run());
|
builder.setPositiveButton(R.string.BlockUnblockDialog_block, (d, w) -> onBlock.run());
|
||||||
} else {
|
} else {
|
||||||
builder.setPositiveButton(R.string.BlockUnblockDialog_block, ((dialog, which) -> onBlock.run()));
|
builder.setPositiveButton(R.string.BlockUnblockDialog_block, ((dialog, which) -> onBlock.run()));
|
||||||
builder.setNegativeButton(android.R.string.cancel, null);
|
builder.setNegativeButton(android.R.string.cancel, null);
|
||||||
|
@ -98,7 +100,7 @@ public final class BlockUnblockDialog {
|
||||||
{
|
{
|
||||||
recipient = recipient.resolve();
|
recipient = recipient.resolve();
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
|
||||||
Resources resources = context.getResources();
|
Resources resources = context.getResources();
|
||||||
|
|
||||||
if (recipient.isGroup()) {
|
if (recipient.isGroup()) {
|
||||||
|
|
|
@ -249,7 +249,6 @@ import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||||
import org.thoughtcrime.securesms.stickers.StickerManagementActivity;
|
import org.thoughtcrime.securesms.stickers.StickerManagementActivity;
|
||||||
import org.thoughtcrime.securesms.stickers.StickerPackInstallEvent;
|
import org.thoughtcrime.securesms.stickers.StickerPackInstallEvent;
|
||||||
import org.thoughtcrime.securesms.stickers.StickerSearchRepository;
|
import org.thoughtcrime.securesms.stickers.StickerSearchRepository;
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
|
||||||
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
|
@ -3369,6 +3368,10 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||||
case ACCEPTED:
|
case ACCEPTED:
|
||||||
hideMessageRequestBusy();
|
hideMessageRequestBusy();
|
||||||
break;
|
break;
|
||||||
|
case BLOCKED_AND_REPORTED:
|
||||||
|
hideMessageRequestBusy();
|
||||||
|
Toast.makeText(this, R.string.ConversationActivity__reported_as_spam_and_blocked, Toast.LENGTH_SHORT).show();
|
||||||
|
break;
|
||||||
case DELETED:
|
case DELETED:
|
||||||
case BLOCKED:
|
case BLOCKED:
|
||||||
hideMessageRequestBusy();
|
hideMessageRequestBusy();
|
||||||
|
@ -3625,7 +3628,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockUnblockDialog.showBlockAndDeleteFor(this, getLifecycle(), recipient, requestModel::onBlock, requestModel::onBlockAndDelete);
|
BlockUnblockDialog.showBlockAndReportSpamFor(this, getLifecycle(), recipient, requestModel::onBlock, requestModel::onBlockAndReportSpam);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onMessageRequestUnblockClicked(@NonNull MessageRequestViewModel requestModel) {
|
private void onMessageRequestUnblockClicked(@NonNull MessageRequestViewModel requestModel) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
|
import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||||
|
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
@ -403,6 +404,25 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NonNull List<ReportSpamData> getReportSpamMessageServerGuids(long threadId, long timestamp) {
|
||||||
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
String query = THREAD_ID + " = ? AND " + getDateReceivedColumnName() + " <= ?";
|
||||||
|
String[] args = SqlUtil.buildArgs(threadId, timestamp);
|
||||||
|
|
||||||
|
List<ReportSpamData> data = new ArrayList<>();
|
||||||
|
try (Cursor cursor = db.query(getTableName(), new String[] { RECIPIENT_ID, SERVER_GUID, getDateReceivedColumnName() }, query, args, null, null, getDateReceivedColumnName() + " DESC", "3")) {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
RecipientId id = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
|
||||||
|
String serverGuid = CursorUtil.requireString(cursor, SERVER_GUID);
|
||||||
|
long dateReceived = CursorUtil.requireLong(cursor, getDateReceivedColumnName());
|
||||||
|
if (!Util.isEmpty(serverGuid)) {
|
||||||
|
data.add(new ReportSpamData(id, serverGuid, dateReceived));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
protected static List<ReactionRecord> parseReactions(@NonNull Cursor cursor) {
|
protected static List<ReactionRecord> parseReactions(@NonNull Cursor cursor) {
|
||||||
byte[] raw = cursor.getBlob(cursor.getColumnIndexOrThrow(REACTIONS));
|
byte[] raw = cursor.getBlob(cursor.getColumnIndexOrThrow(REACTIONS));
|
||||||
|
|
||||||
|
@ -770,4 +790,28 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||||
MessageRecord getCurrent();
|
MessageRecord getCurrent();
|
||||||
void close();
|
void close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ReportSpamData {
|
||||||
|
private final RecipientId recipientId;
|
||||||
|
private final String serverGuid;
|
||||||
|
private final long dateReceived;
|
||||||
|
|
||||||
|
public ReportSpamData(RecipientId recipientId, String serverGuid, long dateReceived) {
|
||||||
|
this.recipientId = recipientId;
|
||||||
|
this.serverGuid = serverGuid;
|
||||||
|
this.dateReceived = dateReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull RecipientId getRecipientId() {
|
||||||
|
return recipientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull String getServerGuid() {
|
||||||
|
return serverGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDateReceived() {
|
||||||
|
return dateReceived;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,8 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
|
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
|
||||||
MENTIONS_SELF + " INTEGER DEFAULT 0, " +
|
MENTIONS_SELF + " INTEGER DEFAULT 0, " +
|
||||||
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0, " +
|
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0, " +
|
||||||
VIEWED_RECEIPT_COUNT + " INTEGER DEFAULT 0);";
|
VIEWED_RECEIPT_COUNT + " INTEGER DEFAULT 0, " +
|
||||||
|
SERVER_GUID + " TEXT DEFAULT NULL);";
|
||||||
|
|
||||||
public static final String[] CREATE_INDEXS = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
||||||
|
@ -1317,6 +1318,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0);
|
contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0);
|
||||||
contentValues.put(READ, retrieved.isExpirationUpdate() ? 1 : 0);
|
contentValues.put(READ, retrieved.isExpirationUpdate() ? 1 : 0);
|
||||||
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
|
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
|
||||||
|
contentValues.put(SERVER_GUID, retrieved.getServerGuid());
|
||||||
|
|
||||||
if (!contentValues.containsKey(DATE_SENT)) {
|
if (!contentValues.containsKey(DATE_SENT)) {
|
||||||
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
||||||
|
|
|
@ -27,6 +27,7 @@ public interface MmsSmsColumns {
|
||||||
public static final String REACTIONS_UNREAD = "reactions_unread";
|
public static final String REACTIONS_UNREAD = "reactions_unread";
|
||||||
public static final String REACTIONS_LAST_SEEN = "reactions_last_seen";
|
public static final String REACTIONS_LAST_SEEN = "reactions_last_seen";
|
||||||
public static final String REMOTE_DELETED = "remote_deleted";
|
public static final String REMOTE_DELETED = "remote_deleted";
|
||||||
|
public static final String SERVER_GUID = "server_guid";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For storage efficiency, all types are stored within a single 64-bit integer column in the
|
* For storage efficiency, all types are stored within a single 64-bit integer column in the
|
||||||
|
|
|
@ -38,11 +38,13 @@ import org.thoughtcrime.securesms.util.CursorUtil;
|
||||||
import org.whispersystems.libsignal.util.Pair;
|
import org.whispersystems.libsignal.util.Pair;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class MmsSmsDatabase extends Database {
|
public class MmsSmsDatabase extends Database {
|
||||||
|
|
||||||
|
@ -564,6 +566,16 @@ public class MmsSmsDatabase extends Database {
|
||||||
DatabaseFactory.getMmsDatabase(context).deleteAbandonedMessages();
|
DatabaseFactory.getMmsDatabase(context).deleteAbandonedMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NonNull List<MessageDatabase.ReportSpamData> getReportSpamMessageServerData(long threadId, long timestamp, int limit) {
|
||||||
|
List<MessageDatabase.ReportSpamData> data = new ArrayList<>();
|
||||||
|
data.addAll(DatabaseFactory.getSmsDatabase(context).getReportSpamMessageServerGuids(threadId, timestamp));
|
||||||
|
data.addAll(DatabaseFactory.getMmsDatabase(context).getReportSpamMessageServerGuids(threadId, timestamp));
|
||||||
|
return data.stream()
|
||||||
|
.sorted((l, r) -> -Long.compare(l.getDateReceived(), r.getDateReceived()))
|
||||||
|
.limit(limit)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
private Cursor queryTables(String[] projection, String selection, String order, String limit) {
|
private Cursor queryTables(String[] projection, String selection, String order, String limit) {
|
||||||
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||||
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||||
|
|
|
@ -9,7 +9,6 @@ import androidx.annotation.NonNull;
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||||
|
@ -68,7 +67,7 @@ public class PushDatabase extends Database {
|
||||||
values.put(TIMESTAMP, envelope.getTimestamp());
|
values.put(TIMESTAMP, envelope.getTimestamp());
|
||||||
values.put(SERVER_RECEIVED_TIMESTAMP, envelope.getServerReceivedTimestamp());
|
values.put(SERVER_RECEIVED_TIMESTAMP, envelope.getServerReceivedTimestamp());
|
||||||
values.put(SERVER_DELIVERED_TIMESTAMP, envelope.getServerDeliveredTimestamp());
|
values.put(SERVER_DELIVERED_TIMESTAMP, envelope.getServerDeliveredTimestamp());
|
||||||
values.put(SERVER_GUID, envelope.getUuid());
|
values.put(SERVER_GUID, envelope.getServerGuid());
|
||||||
|
|
||||||
return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
|
return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,8 @@ public class SmsDatabase extends MessageDatabase {
|
||||||
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
|
REACTIONS_UNREAD + " INTEGER DEFAULT 0, " +
|
||||||
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
|
REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " +
|
||||||
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
|
REMOTE_DELETED + " INTEGER DEFAULT 0, " +
|
||||||
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0);";
|
NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0," +
|
||||||
|
SERVER_GUID + " TEXT DEFAULT NULL);";
|
||||||
|
|
||||||
public static final String[] CREATE_INDEXS = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
||||||
|
@ -1105,6 +1106,7 @@ public class SmsDatabase extends MessageDatabase {
|
||||||
values.put(BODY, message.getMessageBody());
|
values.put(BODY, message.getMessageBody());
|
||||||
values.put(TYPE, type);
|
values.put(TYPE, type);
|
||||||
values.put(THREAD_ID, threadId);
|
values.put(THREAD_ID, threadId);
|
||||||
|
values.put(SERVER_GUID, message.getServerGuid());
|
||||||
|
|
||||||
if (message.isPush() && isDuplicate(message, threadId)) {
|
if (message.isPush() && isDuplicate(message, threadId)) {
|
||||||
Log.w(TAG, "Duplicate message (" + message.getSentTimestampMillis() + "), ignoring...");
|
Log.w(TAG, "Duplicate message (" + message.getSentTimestampMillis() + "), ignoring...");
|
||||||
|
|
|
@ -181,8 +181,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
|
||||||
private static final int CLEAN_REACTION_NOTIFICATIONS = 96;
|
private static final int CLEAN_REACTION_NOTIFICATIONS = 96;
|
||||||
private static final int STORAGE_SERVICE_REFACTOR = 97;
|
private static final int STORAGE_SERVICE_REFACTOR = 97;
|
||||||
private static final int CLEAR_MMS_STORAGE_IDS = 98;
|
private static final int CLEAR_MMS_STORAGE_IDS = 98;
|
||||||
|
private static final int SERVER_GUID = 99;
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 98;
|
private static final int DATABASE_VERSION = 99;
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
@ -1457,6 +1458,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
|
||||||
Log.d(TAG, "Cleared storageIds from " + deleteCount + " rows. They were either MMS groups or empty contacts.");
|
Log.d(TAG, "Cleared storageIds from " + deleteCount + " rows. They were either MMS groups or empty contacts.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < SERVER_GUID) {
|
||||||
|
db.execSQL("ALTER TABLE sms ADD COLUMN server_guid TEXT DEFAULT NULL");
|
||||||
|
db.execSQL("ALTER TABLE mms ADD COLUMN server_guid TEXT DEFAULT NULL");
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
|
|
@ -248,7 +248,7 @@ public final class GroupV1MessageProcessor {
|
||||||
} else {
|
} else {
|
||||||
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||||
String body = Base64.encodeBytes(storage.toByteArray());
|
String body = Base64.encodeBytes(storage.toByteArray());
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), content.getServerReceivedTimestamp(), body, Optional.of(GroupId.v1orThrow(group.getGroupId())), 0, content.isNeedsReceipt());
|
IncomingTextMessage incoming = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(), content.getSenderDevice(), content.getTimestamp(), content.getServerReceivedTimestamp(), body, Optional.of(GroupId.v1orThrow(group.getGroupId())), 0, content.isNeedsReceipt(), content.getServerUuid());
|
||||||
IncomingGroupUpdateMessage groupMessage = new IncomingGroupUpdateMessage(incoming, storage, body);
|
IncomingGroupUpdateMessage groupMessage = new IncomingGroupUpdateMessage(incoming, storage, body);
|
||||||
|
|
||||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
||||||
|
|
|
@ -521,7 +521,7 @@ public final class GroupsV2StateProcessor {
|
||||||
} else {
|
} else {
|
||||||
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||||
RecipientId sender = RecipientId.from(editor.get(), null);
|
RecipientId sender = RecipientId.from(editor.get(), null);
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(sender, -1, timestamp, timestamp, "", Optional.of(groupId), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(sender, -1, timestamp, timestamp, "", Optional.of(groupId), 0, false, null);
|
||||||
IncomingGroupUpdateMessage groupMessage = new IncomingGroupUpdateMessage(incoming, decryptedGroupV2Context);
|
IncomingGroupUpdateMessage groupMessage = new IncomingGroupUpdateMessage(incoming, decryptedGroupV2Context);
|
||||||
|
|
||||||
if (!smsDatabase.insertMessageInbox(groupMessage).isPresent()) {
|
if (!smsDatabase.insertMessageInbox(groupMessage).isPresent()) {
|
||||||
|
|
|
@ -156,6 +156,7 @@ public final class JobManagerFactories {
|
||||||
put(PaymentSendJob.KEY, new PaymentSendJob.Factory());
|
put(PaymentSendJob.KEY, new PaymentSendJob.Factory());
|
||||||
put(PaymentTransactionCheckJob.KEY, new PaymentTransactionCheckJob.Factory());
|
put(PaymentTransactionCheckJob.KEY, new PaymentTransactionCheckJob.Factory());
|
||||||
put(ProfileUploadJob.KEY, new ProfileUploadJob.Factory());
|
put(ProfileUploadJob.KEY, new ProfileUploadJob.Factory());
|
||||||
|
put(ReportSpamJob.KEY, new ReportSpamJob.Factory());
|
||||||
|
|
||||||
// Migrations
|
// Migrations
|
||||||
put(AccountRecordMigrationJob.KEY, new AccountRecordMigrationJob.Factory());
|
put(AccountRecordMigrationJob.KEY, new AccountRecordMigrationJob.Factory());
|
||||||
|
|
|
@ -51,14 +51,18 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob {
|
||||||
return new MultiDeviceMessageRequestResponseJob(threadRecipient, Type.BLOCK_AND_DELETE);
|
return new MultiDeviceMessageRequestResponseJob(threadRecipient, Type.BLOCK_AND_DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiDeviceMessageRequestResponseJob(@NonNull RecipientId threadRecipient, @NonNull Type type) {
|
public static @NonNull MultiDeviceMessageRequestResponseJob forBlockAndReportSpam(@NonNull RecipientId threadRecipient) {
|
||||||
this(new Parameters.Builder()
|
return new MultiDeviceMessageRequestResponseJob(threadRecipient, Type.BLOCK);
|
||||||
.setQueue("MultiDeviceMessageRequestResponseJob")
|
}
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
|
||||||
.setMaxAttempts(Parameters.UNLIMITED)
|
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
|
||||||
.build(), threadRecipient, type);
|
|
||||||
|
|
||||||
|
private MultiDeviceMessageRequestResponseJob(@NonNull RecipientId threadRecipient, @NonNull Type type) {
|
||||||
|
this(new Parameters.Builder().setQueue("MultiDeviceMessageRequestResponseJob")
|
||||||
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
|
.setMaxAttempts(Parameters.UNLIMITED)
|
||||||
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
|
.build(),
|
||||||
|
threadRecipient,
|
||||||
|
type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiDeviceMessageRequestResponseJob(@NonNull Parameters parameters,
|
private MultiDeviceMessageRequestResponseJob(@NonNull Parameters parameters,
|
||||||
|
@ -111,11 +115,16 @@ public class MultiDeviceMessageRequestResponseJob extends BaseJob {
|
||||||
|
|
||||||
private static MessageRequestResponseMessage.Type localToRemoteType(@NonNull Type type) {
|
private static MessageRequestResponseMessage.Type localToRemoteType(@NonNull Type type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ACCEPT: return MessageRequestResponseMessage.Type.ACCEPT;
|
case ACCEPT:
|
||||||
case DELETE: return MessageRequestResponseMessage.Type.DELETE;
|
return MessageRequestResponseMessage.Type.ACCEPT;
|
||||||
case BLOCK: return MessageRequestResponseMessage.Type.BLOCK;
|
case DELETE:
|
||||||
case BLOCK_AND_DELETE: return MessageRequestResponseMessage.Type.BLOCK_AND_DELETE;
|
return MessageRequestResponseMessage.Type.DELETE;
|
||||||
default: return MessageRequestResponseMessage.Type.UNKNOWN;
|
case BLOCK:
|
||||||
|
return MessageRequestResponseMessage.Type.BLOCK;
|
||||||
|
case BLOCK_AND_DELETE:
|
||||||
|
return MessageRequestResponseMessage.Type.BLOCK_AND_DELETE;
|
||||||
|
default:
|
||||||
|
return MessageRequestResponseMessage.Type.UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.signal.core.util.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.database.MessageDatabase.ReportSpamData;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||||
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||||
|
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||||
|
import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report 1 to {@link #MAX_MESSAGE_COUNT} message guids received prior to {@link #timestamp} in {@link #threadId} to the server as spam.
|
||||||
|
*/
|
||||||
|
public class ReportSpamJob extends BaseJob {
|
||||||
|
|
||||||
|
public static final String KEY = "ReportSpamJob";
|
||||||
|
private static final String TAG = Log.tag(ReportSpamJob.class);
|
||||||
|
|
||||||
|
private static final String KEY_THREAD_ID = "thread_id";
|
||||||
|
private static final String KEY_TIMESTAMP = "timestamp";
|
||||||
|
private static final int MAX_MESSAGE_COUNT = 3;
|
||||||
|
|
||||||
|
private final long threadId;
|
||||||
|
private final long timestamp;
|
||||||
|
|
||||||
|
public ReportSpamJob(long threadId, long timestamp) {
|
||||||
|
this(new Parameters.Builder().addConstraint(NetworkConstraint.KEY)
|
||||||
|
.setMaxAttempts(5)
|
||||||
|
.setQueue("ReportSpamJob")
|
||||||
|
.build(),
|
||||||
|
threadId,
|
||||||
|
timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReportSpamJob(@NonNull Parameters parameters, long threadId, long timestamp) {
|
||||||
|
super(parameters);
|
||||||
|
this.threadId = threadId;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull Data serialize() {
|
||||||
|
return new Data.Builder().putLong(KEY_THREAD_ID, threadId)
|
||||||
|
.putLong(KEY_TIMESTAMP, timestamp)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull String getFactoryKey() {
|
||||||
|
return KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRun() throws IOException {
|
||||||
|
if (!TextSecurePreferences.isPushRegistered(context)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
List<ReportSpamData> reportSpamData = DatabaseFactory.getMmsSmsDatabase(context).getReportSpamMessageServerData(threadId, timestamp, MAX_MESSAGE_COUNT);
|
||||||
|
SignalServiceAccountManager signalServiceAccountManager = ApplicationDependencies.getSignalServiceAccountManager();
|
||||||
|
for (ReportSpamData data : reportSpamData) {
|
||||||
|
Optional<String> e164 = Recipient.resolved(data.getRecipientId()).getE164();
|
||||||
|
if (e164.isPresent()) {
|
||||||
|
signalServiceAccountManager.reportSpam(e164.get(), data.getServerGuid());
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Unable to report spam without an e164 for " + data.getRecipientId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Reported " + count + " out of " + reportSpamData.size() + " messages in thread " + threadId + " as spam");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onShouldRetry(@NonNull Exception exception) {
|
||||||
|
if (exception instanceof ServerRejectedException) {
|
||||||
|
return false;
|
||||||
|
} else if (exception instanceof NonSuccessfulResponseCodeException) {
|
||||||
|
return ((NonSuccessfulResponseCodeException) exception).is5xx();
|
||||||
|
}
|
||||||
|
|
||||||
|
return exception instanceof IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure() {
|
||||||
|
Log.w(TAG, "Canceling report spam for thread " + threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Factory implements Job.Factory<ReportSpamJob> {
|
||||||
|
@Override
|
||||||
|
public @NonNull ReportSpamJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||||
|
return new ReportSpamJob(parameters, data.getLong(KEY_THREAD_ID), data.getLong(KEY_TIMESTAMP));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
|
||||||
|
import org.thoughtcrime.securesms.jobs.ReportSpamJob;
|
||||||
import org.thoughtcrime.securesms.jobs.SendViewedReceiptJob;
|
import org.thoughtcrime.securesms.jobs.SendViewedReceiptJob;
|
||||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||||
|
@ -226,10 +227,10 @@ final class MessageRequestRepository {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockAndDeleteMessageRequest(@NonNull LiveRecipient liveRecipient,
|
void blockAndReportSpamMessageRequest(@NonNull LiveRecipient liveRecipient,
|
||||||
long threadId,
|
long threadId,
|
||||||
@NonNull Runnable onMessageRequestBlocked,
|
@NonNull Runnable onMessageRequestBlocked,
|
||||||
@NonNull GroupChangeErrorCallback error)
|
@NonNull GroupChangeErrorCallback error)
|
||||||
{
|
{
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
Recipient recipient = liveRecipient.resolve();
|
Recipient recipient = liveRecipient.resolve();
|
||||||
|
@ -242,10 +243,10 @@ final class MessageRequestRepository {
|
||||||
}
|
}
|
||||||
liveRecipient.refresh();
|
liveRecipient.refresh();
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).deleteConversation(threadId);
|
ApplicationDependencies.getJobManager().add(new ReportSpamJob(threadId, System.currentTimeMillis()));
|
||||||
|
|
||||||
if (TextSecurePreferences.isMultiDevice(context)) {
|
if (TextSecurePreferences.isMultiDevice(context)) {
|
||||||
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forBlockAndDelete(liveRecipient.getId()));
|
ApplicationDependencies.getJobManager().add(MultiDeviceMessageRequestResponseJob.forBlockAndReportSpam(liveRecipient.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageRequestBlocked.run();
|
onMessageRequestBlocked.run();
|
||||||
|
|
|
@ -8,7 +8,6 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.Transformations;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
@ -20,7 +19,6 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataTriple;
|
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
import org.thoughtcrime.securesms.util.livedata.Store;
|
import org.thoughtcrime.securesms.util.livedata.Store;
|
||||||
|
|
||||||
|
@ -29,16 +27,16 @@ import java.util.List;
|
||||||
|
|
||||||
public class MessageRequestViewModel extends ViewModel {
|
public class MessageRequestViewModel extends ViewModel {
|
||||||
|
|
||||||
private final SingleLiveEvent<Status> status = new SingleLiveEvent<>();
|
private final SingleLiveEvent<Status> status = new SingleLiveEvent<>();
|
||||||
private final SingleLiveEvent<GroupChangeFailureReason> failures = new SingleLiveEvent<>();
|
private final SingleLiveEvent<GroupChangeFailureReason> failures = new SingleLiveEvent<>();
|
||||||
private final MutableLiveData<Recipient> recipient = new MutableLiveData<>();
|
private final MutableLiveData<Recipient> recipient = new MutableLiveData<>();
|
||||||
private final LiveData<MessageData> messageData;
|
private final MutableLiveData<List<String>> groups = new MutableLiveData<>(Collections.emptyList());
|
||||||
private final MutableLiveData<List<String>> groups = new MutableLiveData<>(Collections.emptyList());
|
private final MutableLiveData<GroupInfo> groupInfo = new MutableLiveData<>(GroupInfo.ZERO);
|
||||||
private final MutableLiveData<GroupInfo> groupInfo = new MutableLiveData<>(GroupInfo.ZERO);
|
|
||||||
private final LiveData<RequestReviewDisplayState> requestReviewDisplayState;
|
|
||||||
private final Store<RecipientInfo> recipientInfoStore = new Store<>(new RecipientInfo(null, null, null, null));
|
private final Store<RecipientInfo> recipientInfoStore = new Store<>(new RecipientInfo(null, null, null, null));
|
||||||
|
|
||||||
private final MessageRequestRepository repository;
|
private final LiveData<MessageData> messageData;
|
||||||
|
private final LiveData<RequestReviewDisplayState> requestReviewDisplayState;
|
||||||
|
private final MessageRequestRepository repository;
|
||||||
|
|
||||||
private LiveRecipient liveRecipient;
|
private LiveRecipient liveRecipient;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
|
@ -142,11 +140,11 @@ public class MessageRequestViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
public void onBlockAndDelete() {
|
public void onBlockAndReportSpam() {
|
||||||
repository.blockAndDeleteMessageRequest(liveRecipient,
|
repository.blockAndReportSpamMessageRequest(liveRecipient,
|
||||||
threadId,
|
threadId,
|
||||||
() -> status.postValue(Status.BLOCKED),
|
() -> status.postValue(Status.BLOCKED_AND_REPORTED),
|
||||||
this::onGroupChangeError);
|
this::onGroupChangeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onGroupChangeError(@NonNull GroupChangeFailureReason error) {
|
private void onGroupChangeError(@NonNull GroupChangeFailureReason error) {
|
||||||
|
@ -187,8 +185,8 @@ public class MessageRequestViewModel extends ViewModel {
|
||||||
|
|
||||||
public static class RecipientInfo {
|
public static class RecipientInfo {
|
||||||
@Nullable private final Recipient recipient;
|
@Nullable private final Recipient recipient;
|
||||||
@NonNull private final GroupInfo groupInfo;
|
@NonNull private final GroupInfo groupInfo;
|
||||||
@NonNull private final List<String> sharedGroups;
|
@NonNull private final List<String> sharedGroups;
|
||||||
@Nullable private final MessageRequestState messageRequestState;
|
@Nullable private final MessageRequestState messageRequestState;
|
||||||
|
|
||||||
private RecipientInfo(@Nullable Recipient recipient, @Nullable GroupInfo groupInfo, @Nullable List<String> sharedGroups, @Nullable MessageRequestState messageRequestState) {
|
private RecipientInfo(@Nullable Recipient recipient, @Nullable GroupInfo groupInfo, @Nullable List<String> sharedGroups, @Nullable MessageRequestState messageRequestState) {
|
||||||
|
@ -230,6 +228,7 @@ public class MessageRequestViewModel extends ViewModel {
|
||||||
IDLE,
|
IDLE,
|
||||||
BLOCKING,
|
BLOCKING,
|
||||||
BLOCKED,
|
BLOCKED,
|
||||||
|
BLOCKED_AND_REPORTED,
|
||||||
DELETING,
|
DELETING,
|
||||||
DELETED,
|
DELETED,
|
||||||
ACCEPTING,
|
ACCEPTING,
|
||||||
|
@ -243,7 +242,7 @@ public class MessageRequestViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class MessageData {
|
public static final class MessageData {
|
||||||
private final Recipient recipient;
|
private final Recipient recipient;
|
||||||
private final MessageRequestState messageState;
|
private final MessageRequestState messageState;
|
||||||
|
|
||||||
public MessageData(@NonNull Recipient recipient, @NonNull MessageRequestState messageState) {
|
public MessageData(@NonNull Recipient recipient, @NonNull MessageRequestState messageState) {
|
||||||
|
|
|
@ -576,11 +576,14 @@ public final class MessageContentProcessor {
|
||||||
{
|
{
|
||||||
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(),
|
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Recipient.externalHighTrustPush(context, content.getSender()).getId(),
|
||||||
content.getSenderDevice(),
|
content.getSenderDevice(),
|
||||||
content.getTimestamp(),
|
content.getTimestamp(),
|
||||||
content.getServerReceivedTimestamp(),
|
content.getServerReceivedTimestamp(),
|
||||||
"", Optional.absent(), 0,
|
"",
|
||||||
content.isNeedsReceipt());
|
Optional.absent(),
|
||||||
|
0,
|
||||||
|
content.isNeedsReceipt(),
|
||||||
|
content.getServerUuid());
|
||||||
|
|
||||||
Long threadId;
|
Long threadId;
|
||||||
|
|
||||||
|
@ -686,21 +689,22 @@ public final class MessageContentProcessor {
|
||||||
MessageDatabase database = DatabaseFactory.getMmsDatabase(context);
|
MessageDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
|
Recipient sender = Recipient.externalHighTrustPush(context, content.getSender());
|
||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(sender.getId(),
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(sender.getId(),
|
||||||
content.getTimestamp(),
|
content.getTimestamp(),
|
||||||
content.getServerReceivedTimestamp(),
|
content.getServerReceivedTimestamp(),
|
||||||
-1,
|
-1,
|
||||||
expiresInSeconds * 1000L,
|
expiresInSeconds * 1000L,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
content.isNeedsReceipt(),
|
content.isNeedsReceipt(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
groupContext,
|
groupContext,
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent());
|
Optional.absent(),
|
||||||
|
content.getServerUuid());
|
||||||
|
|
||||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||||
|
|
||||||
|
@ -1104,22 +1108,24 @@ public final class MessageContentProcessor {
|
||||||
Optional<List<LinkPreview>> linkPreviews = getLinkPreviews(message.getPreviews(), message.getBody().or(""));
|
Optional<List<LinkPreview>> linkPreviews = getLinkPreviews(message.getPreviews(), message.getBody().or(""));
|
||||||
Optional<List<Mention>> mentions = getMentions(message.getMentions());
|
Optional<List<Mention>> mentions = getMentions(message.getMentions());
|
||||||
Optional<Attachment> sticker = getStickerAttachment(message.getSticker());
|
Optional<Attachment> sticker = getStickerAttachment(message.getSticker());
|
||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(RecipientId.fromHighTrust(content.getSender()),
|
|
||||||
message.getTimestamp(),
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(RecipientId.fromHighTrust(content.getSender()),
|
||||||
content.getServerReceivedTimestamp(),
|
message.getTimestamp(),
|
||||||
-1,
|
content.getServerReceivedTimestamp(),
|
||||||
message.getExpiresInSeconds() * 1000L,
|
-1,
|
||||||
false,
|
message.getExpiresInSeconds() * 1000L,
|
||||||
message.isViewOnce(),
|
false,
|
||||||
content.isNeedsReceipt(),
|
message.isViewOnce(),
|
||||||
message.getBody(),
|
content.isNeedsReceipt(),
|
||||||
message.getGroupContext(),
|
message.getBody(),
|
||||||
message.getAttachments(),
|
message.getGroupContext(),
|
||||||
quote,
|
message.getAttachments(),
|
||||||
sharedContacts,
|
quote,
|
||||||
linkPreviews,
|
sharedContacts,
|
||||||
mentions,
|
linkPreviews,
|
||||||
sticker);
|
mentions,
|
||||||
|
sticker,
|
||||||
|
content.getServerUuid());
|
||||||
|
|
||||||
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||||
|
|
||||||
|
@ -1328,13 +1334,14 @@ public final class MessageContentProcessor {
|
||||||
notifyTypingStoppedFromIncomingMessage(recipient, content.getSender(), content.getSenderDevice());
|
notifyTypingStoppedFromIncomingMessage(recipient, content.getSender(), content.getSenderDevice());
|
||||||
|
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(RecipientId.fromHighTrust(content.getSender()),
|
IncomingTextMessage textMessage = new IncomingTextMessage(RecipientId.fromHighTrust(content.getSender()),
|
||||||
content.getSenderDevice(),
|
content.getSenderDevice(),
|
||||||
message.getTimestamp(),
|
message.getTimestamp(),
|
||||||
content.getServerReceivedTimestamp(),
|
content.getServerReceivedTimestamp(),
|
||||||
body,
|
body,
|
||||||
groupId,
|
groupId,
|
||||||
message.getExpiresInSeconds() * 1000L,
|
message.getExpiresInSeconds() * 1000L,
|
||||||
content.isNeedsReceipt());
|
content.isNeedsReceipt(),
|
||||||
|
content.getServerUuid());
|
||||||
|
|
||||||
textMessage = new IncomingEncryptedMessage(textMessage, body);
|
textMessage = new IncomingEncryptedMessage(textMessage, body);
|
||||||
Optional<InsertResult> insertResult = database.insertMessageInbox(textMessage);
|
Optional<InsertResult> insertResult = database.insertMessageInbox(textMessage);
|
||||||
|
@ -1803,8 +1810,8 @@ public final class MessageContentProcessor {
|
||||||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional<GroupId> groupId) {
|
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional<GroupId> groupId) {
|
||||||
MessageDatabase database = DatabaseFactory.getSmsDatabase(context);
|
MessageDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, sender).getId(),
|
IncomingTextMessage textMessage = new IncomingTextMessage(Recipient.external(context, sender).getId(),
|
||||||
senderDevice, timestamp, -1, "",
|
senderDevice, timestamp, -1, "",
|
||||||
groupId, 0, false);
|
groupId, 0, false, null);
|
||||||
|
|
||||||
textMessage = new IncomingEncryptedMessage(textMessage, "");
|
textMessage = new IncomingEncryptedMessage(textMessage, "");
|
||||||
return database.insertMessageInbox(textMessage);
|
return database.insertMessageInbox(textMessage);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.thoughtcrime.securesms.mms;
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.PointerAttachment;
|
import org.thoughtcrime.securesms.attachments.PointerAttachment;
|
||||||
|
@ -32,6 +33,7 @@ public class IncomingMediaMessage {
|
||||||
private final QuoteModel quote;
|
private final QuoteModel quote;
|
||||||
private final boolean unidentified;
|
private final boolean unidentified;
|
||||||
private final boolean viewOnce;
|
private final boolean viewOnce;
|
||||||
|
private final String serverGuid;
|
||||||
|
|
||||||
private final List<Attachment> attachments = new LinkedList<>();
|
private final List<Attachment> attachments = new LinkedList<>();
|
||||||
private final List<Contact> sharedContacts = new LinkedList<>();
|
private final List<Contact> sharedContacts = new LinkedList<>();
|
||||||
|
@ -63,6 +65,7 @@ public class IncomingMediaMessage {
|
||||||
this.viewOnce = viewOnce;
|
this.viewOnce = viewOnce;
|
||||||
this.quote = null;
|
this.quote = null;
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
|
this.serverGuid = null;
|
||||||
|
|
||||||
this.attachments.addAll(attachments);
|
this.attachments.addAll(attachments);
|
||||||
this.sharedContacts.addAll(sharedContacts.or(Collections.emptyList()));
|
this.sharedContacts.addAll(sharedContacts.or(Collections.emptyList()));
|
||||||
|
@ -84,7 +87,8 @@ public class IncomingMediaMessage {
|
||||||
Optional<List<Contact>> sharedContacts,
|
Optional<List<Contact>> sharedContacts,
|
||||||
Optional<List<LinkPreview>> linkPreviews,
|
Optional<List<LinkPreview>> linkPreviews,
|
||||||
Optional<List<Mention>> mentions,
|
Optional<List<Mention>> mentions,
|
||||||
Optional<Attachment> sticker)
|
Optional<Attachment> sticker,
|
||||||
|
@Nullable String serverGuid)
|
||||||
{
|
{
|
||||||
this.push = true;
|
this.push = true;
|
||||||
this.from = from;
|
this.from = from;
|
||||||
|
@ -109,6 +113,8 @@ public class IncomingMediaMessage {
|
||||||
if (sticker.isPresent()) {
|
if (sticker.isPresent()) {
|
||||||
this.attachments.add(sticker.get());
|
this.attachments.add(sticker.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.serverGuid = serverGuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSubscriptionId() {
|
public int getSubscriptionId() {
|
||||||
|
@ -178,4 +184,8 @@ public class IncomingMediaMessage {
|
||||||
public boolean isUnidentified() {
|
public boolean isUnidentified() {
|
||||||
return unidentified;
|
return unidentified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable String getServerGuid() {
|
||||||
|
return serverGuid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
public class IncomingJoinedMessage extends IncomingTextMessage {
|
public class IncomingJoinedMessage extends IncomingTextMessage {
|
||||||
|
|
||||||
public IncomingJoinedMessage(RecipientId sender) {
|
public IncomingJoinedMessage(RecipientId sender) {
|
||||||
super(sender, 1, System.currentTimeMillis(), -1, null, Optional.absent(), 0, false);
|
super(sender, 1, System.currentTimeMillis(), -1, null, Optional.absent(), 0, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresInMillis;
|
private final long expiresInMillis;
|
||||||
private final boolean unidentified;
|
private final boolean unidentified;
|
||||||
|
@Nullable private final String serverGuid;
|
||||||
|
|
||||||
public IncomingTextMessage(@NonNull RecipientId sender, @NonNull SmsMessage message, int subscriptionId) {
|
public IncomingTextMessage(@NonNull RecipientId sender, @NonNull SmsMessage message, int subscriptionId) {
|
||||||
this.message = message.getDisplayMessageBody();
|
this.message = message.getDisplayMessageBody();
|
||||||
|
@ -60,6 +61,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.groupId = null;
|
this.groupId = null;
|
||||||
this.push = false;
|
this.push = false;
|
||||||
this.unidentified = false;
|
this.unidentified = false;
|
||||||
|
this.serverGuid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(@NonNull RecipientId sender,
|
public IncomingTextMessage(@NonNull RecipientId sender,
|
||||||
|
@ -69,7 +71,8 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
String encodedBody,
|
String encodedBody,
|
||||||
Optional<GroupId> groupId,
|
Optional<GroupId> groupId,
|
||||||
long expiresInMillis,
|
long expiresInMillis,
|
||||||
boolean unidentified)
|
boolean unidentified,
|
||||||
|
String serverGuid)
|
||||||
{
|
{
|
||||||
this.message = encodedBody;
|
this.message = encodedBody;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -85,6 +88,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.expiresInMillis = expiresInMillis;
|
this.expiresInMillis = expiresInMillis;
|
||||||
this.unidentified = unidentified;
|
this.unidentified = unidentified;
|
||||||
this.groupId = groupId.orNull();
|
this.groupId = groupId.orNull();
|
||||||
|
this.serverGuid = serverGuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(Parcel in) {
|
public IncomingTextMessage(Parcel in) {
|
||||||
|
@ -102,6 +106,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.subscriptionId = in.readInt();
|
this.subscriptionId = in.readInt();
|
||||||
this.expiresInMillis = in.readLong();
|
this.expiresInMillis = in.readLong();
|
||||||
this.unidentified = in.readInt() == 1;
|
this.unidentified = in.readInt() == 1;
|
||||||
|
this.serverGuid = in.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(IncomingTextMessage base, String newBody) {
|
public IncomingTextMessage(IncomingTextMessage base, String newBody) {
|
||||||
|
@ -119,6 +124,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.subscriptionId = base.getSubscriptionId();
|
this.subscriptionId = base.getSubscriptionId();
|
||||||
this.expiresInMillis = base.getExpiresIn();
|
this.expiresInMillis = base.getExpiresIn();
|
||||||
this.unidentified = base.isUnidentified();
|
this.unidentified = base.isUnidentified();
|
||||||
|
this.serverGuid = base.getServerGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(List<IncomingTextMessage> fragments) {
|
public IncomingTextMessage(List<IncomingTextMessage> fragments) {
|
||||||
|
@ -142,6 +148,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
||||||
this.expiresInMillis = fragments.get(0).getExpiresIn();
|
this.expiresInMillis = fragments.get(0).getExpiresIn();
|
||||||
this.unidentified = fragments.get(0).isUnidentified();
|
this.unidentified = fragments.get(0).isUnidentified();
|
||||||
|
this.serverGuid = fragments.get(0).getServerGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IncomingTextMessage(@NonNull RecipientId sender, @Nullable GroupId groupId)
|
protected IncomingTextMessage(@NonNull RecipientId sender, @Nullable GroupId groupId)
|
||||||
|
@ -160,6 +167,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
this.subscriptionId = -1;
|
this.subscriptionId = -1;
|
||||||
this.expiresInMillis = 0;
|
this.expiresInMillis = 0;
|
||||||
this.unidentified = false;
|
this.unidentified = false;
|
||||||
|
this.serverGuid = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSubscriptionId() {
|
public int getSubscriptionId() {
|
||||||
|
@ -265,6 +273,10 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
return unidentified;
|
return unidentified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable String getServerGuid() {
|
||||||
|
return serverGuid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -285,5 +297,6 @@ public class IncomingTextMessage implements Parcelable {
|
||||||
out.writeInt(subscriptionId);
|
out.writeInt(subscriptionId);
|
||||||
out.writeLong(expiresInMillis);
|
out.writeLong(expiresInMillis);
|
||||||
out.writeInt(unidentified ? 1 : 0);
|
out.writeInt(unidentified ? 1 : 0);
|
||||||
|
out.writeString(serverGuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ public final class IdentityUtil {
|
||||||
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
if (groupRecord.getMembers().contains(recipient.getId()) && groupRecord.isActive() && !groupRecord.isMms()) {
|
||||||
|
|
||||||
if (remote) {
|
if (remote) {
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.of(groupRecord.getId()), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.of(groupRecord.getId()), 0, false, null);
|
||||||
|
|
||||||
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||||
|
@ -96,7 +96,7 @@ public final class IdentityUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remote) {
|
if (remote) {
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.absent(), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(recipient.getId(), 1, time, -1, null, Optional.absent(), 0, false, null);
|
||||||
|
|
||||||
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming);
|
||||||
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
else incoming = new IncomingIdentityDefaultMessage(incoming);
|
||||||
|
@ -125,7 +125,7 @@ public final class IdentityUtil {
|
||||||
|
|
||||||
while ((groupRecord = reader.getNext()) != null) {
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
if (groupRecord.getMembers().contains(recipientId) && groupRecord.isActive()) {
|
if (groupRecord.getMembers().contains(recipientId) && groupRecord.isActive()) {
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(recipientId, 1, time, time, null, Optional.of(groupRecord.getId()), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(recipientId, 1, time, time, null, Optional.of(groupRecord.getId()), 0, false, null);
|
||||||
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
|
|
||||||
smsDatabase.insertMessageInbox(groupUpdate);
|
smsDatabase.insertMessageInbox(groupUpdate);
|
||||||
|
@ -133,7 +133,7 @@ public final class IdentityUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(recipientId, 1, time, -1, null, Optional.absent(), 0, false);
|
IncomingTextMessage incoming = new IncomingTextMessage(recipientId, 1, time, -1, null, Optional.absent(), 0, false, null);
|
||||||
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
|
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
|
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
<string name="BlockUnblockDialog_unblock_s">Unblock %1$s?</string>
|
<string name="BlockUnblockDialog_unblock_s">Unblock %1$s?</string>
|
||||||
<string name="BlockUnblockDialog_block">Block</string>
|
<string name="BlockUnblockDialog_block">Block</string>
|
||||||
<string name="BlockUnblockDialog_block_and_leave">Block and Leave</string>
|
<string name="BlockUnblockDialog_block_and_leave">Block and Leave</string>
|
||||||
<string name="BlockUnblockDialog_block_and_delete">Block and Delete</string>
|
<string name="BlockUnblockDialog_report_spam_and_block">Report spam and block</string>
|
||||||
|
|
||||||
<!-- BucketedThreadMedia -->
|
<!-- BucketedThreadMedia -->
|
||||||
<string name="BucketedThreadMedia_Today">Today</string>
|
<string name="BucketedThreadMedia_Today">Today</string>
|
||||||
|
@ -285,6 +285,8 @@
|
||||||
|
|
||||||
<string name="ConversationActivity_error_sending_media">Error sending media</string>
|
<string name="ConversationActivity_error_sending_media">Error sending media</string>
|
||||||
|
|
||||||
|
<string name="ConversationActivity__reported_as_spam_and_blocked">Reported as spam and blocked.</string>
|
||||||
|
|
||||||
<!-- ConversationAdapter -->
|
<!-- ConversationAdapter -->
|
||||||
<plurals name="ConversationAdapter_n_unread_messages">
|
<plurals name="ConversationAdapter_n_unread_messages">
|
||||||
<item quantity="one">%d unread message</item>
|
<item quantity="one">%d unread message</item>
|
||||||
|
|
|
@ -641,6 +641,10 @@ public class SignalServiceAccountManager {
|
||||||
return this.pushServiceSocket.getCurrencyConversions();
|
return this.pushServiceSocket.getCurrencyConversions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reportSpam(String e164, String serverGuid) throws IOException {
|
||||||
|
this.pushServiceSocket.reportSpam(e164, serverGuid);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The avatar URL path, if one was written.
|
* @return The avatar URL path, if one was written.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
package org.whispersystems.signalservice.api;
|
package org.whispersystems.signalservice.api;
|
||||||
|
|
||||||
import org.signal.zkgroup.VerificationFailedException;
|
|
||||||
import org.signal.zkgroup.profiles.ClientZkProfileOperations;
|
import org.signal.zkgroup.profiles.ClientZkProfileOperations;
|
||||||
import org.signal.zkgroup.profiles.ProfileKey;
|
import org.signal.zkgroup.profiles.ProfileKey;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
|
@ -23,8 +22,6 @@ import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
|
||||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
|
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
|
||||||
import org.whispersystems.signalservice.api.util.CredentialsProvider;
|
import org.whispersystems.signalservice.api.util.CredentialsProvider;
|
||||||
import org.whispersystems.signalservice.api.util.SleepTimer;
|
import org.whispersystems.signalservice.api.util.SleepTimer;
|
||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
|
@ -300,8 +297,11 @@ public class SignalServiceMessageReceiver {
|
||||||
callback.onMessage(envelope);
|
callback.onMessage(envelope);
|
||||||
results.add(envelope);
|
results.add(envelope);
|
||||||
|
|
||||||
if (envelope.hasUuid()) socket.acknowledgeMessage(envelope.getUuid());
|
if (envelope.hasServerGuid()) {
|
||||||
else socket.acknowledgeMessage(entity.getSourceE164(), entity.getTimestamp());
|
socket.acknowledgeMessage(envelope.getServerGuid());
|
||||||
|
} else {
|
||||||
|
socket.acknowledgeMessage(entity.getSourceE164(), entity.getTimestamp());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|
|
@ -180,14 +180,14 @@ public class SignalServiceCipher {
|
||||||
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
|
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
|
||||||
|
|
||||||
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
|
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
|
||||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false);
|
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid());
|
||||||
sessionVersion = sessionCipher.getSessionVersion();
|
sessionVersion = sessionCipher.getSessionVersion();
|
||||||
} else if (envelope.isSignalMessage()) {
|
} else if (envelope.isSignalMessage()) {
|
||||||
SignalProtocolAddress sourceAddress = getPreferredProtocolAddress(signalProtocolStore, envelope.getSourceAddress(), envelope.getSourceDevice());
|
SignalProtocolAddress sourceAddress = getPreferredProtocolAddress(signalProtocolStore, envelope.getSourceAddress(), envelope.getSourceDevice());
|
||||||
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
|
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
|
||||||
|
|
||||||
paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
|
paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
|
||||||
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false);
|
metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid());
|
||||||
sessionVersion = sessionCipher.getSessionVersion();
|
sessionVersion = sessionCipher.getSessionVersion();
|
||||||
} else if (envelope.isUnidentifiedSender()) {
|
} else if (envelope.isUnidentifiedSender()) {
|
||||||
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getUuid().orNull(), localAddress.getNumber().orNull(), 1));
|
SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getUuid().orNull(), localAddress.getNumber().orNull(), 1));
|
||||||
|
@ -196,7 +196,7 @@ public class SignalServiceCipher {
|
||||||
SignalProtocolAddress protocolAddress = getPreferredProtocolAddress(signalProtocolStore, resultAddress, result.getDeviceId());
|
SignalProtocolAddress protocolAddress = getPreferredProtocolAddress(signalProtocolStore, resultAddress, result.getDeviceId());
|
||||||
|
|
||||||
paddedMessage = result.getPaddedMessage();
|
paddedMessage = result.getPaddedMessage();
|
||||||
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), true);
|
metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), true, envelope.getServerGuid());
|
||||||
sessionVersion = sealedSessionCipher.getSessionVersion(protocolAddress);
|
sessionVersion = sealedSessionCipher.getSessionVersion(protocolAddress);
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
|
throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
|
||||||
|
|
|
@ -69,6 +69,7 @@ public final class SignalServiceContent {
|
||||||
private final long serverDeliveredTimestamp;
|
private final long serverDeliveredTimestamp;
|
||||||
private final boolean needsReceipt;
|
private final boolean needsReceipt;
|
||||||
private final SignalServiceContentProto serializedState;
|
private final SignalServiceContentProto serializedState;
|
||||||
|
private final String serverUuid;
|
||||||
|
|
||||||
private final Optional<SignalServiceDataMessage> message;
|
private final Optional<SignalServiceDataMessage> message;
|
||||||
private final Optional<SignalServiceSyncMessage> synchronizeMessage;
|
private final Optional<SignalServiceSyncMessage> synchronizeMessage;
|
||||||
|
@ -83,6 +84,7 @@ public final class SignalServiceContent {
|
||||||
long serverReceivedTimestamp,
|
long serverReceivedTimestamp,
|
||||||
long serverDeliveredTimestamp,
|
long serverDeliveredTimestamp,
|
||||||
boolean needsReceipt,
|
boolean needsReceipt,
|
||||||
|
String serverUuid,
|
||||||
SignalServiceContentProto serializedState)
|
SignalServiceContentProto serializedState)
|
||||||
{
|
{
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -91,6 +93,7 @@ public final class SignalServiceContent {
|
||||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
this.needsReceipt = needsReceipt;
|
this.needsReceipt = needsReceipt;
|
||||||
|
this.serverUuid = serverUuid;
|
||||||
this.serializedState = serializedState;
|
this.serializedState = serializedState;
|
||||||
|
|
||||||
this.message = Optional.fromNullable(message);
|
this.message = Optional.fromNullable(message);
|
||||||
|
@ -107,6 +110,7 @@ public final class SignalServiceContent {
|
||||||
long serverReceivedTimestamp,
|
long serverReceivedTimestamp,
|
||||||
long serverDeliveredTimestamp,
|
long serverDeliveredTimestamp,
|
||||||
boolean needsReceipt,
|
boolean needsReceipt,
|
||||||
|
String serverUuid,
|
||||||
SignalServiceContentProto serializedState)
|
SignalServiceContentProto serializedState)
|
||||||
{
|
{
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -115,6 +119,7 @@ public final class SignalServiceContent {
|
||||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
this.needsReceipt = needsReceipt;
|
this.needsReceipt = needsReceipt;
|
||||||
|
this.serverUuid = serverUuid;
|
||||||
this.serializedState = serializedState;
|
this.serializedState = serializedState;
|
||||||
|
|
||||||
this.message = Optional.absent();
|
this.message = Optional.absent();
|
||||||
|
@ -131,6 +136,7 @@ public final class SignalServiceContent {
|
||||||
long serverReceivedTimestamp,
|
long serverReceivedTimestamp,
|
||||||
long serverDeliveredTimestamp,
|
long serverDeliveredTimestamp,
|
||||||
boolean needsReceipt,
|
boolean needsReceipt,
|
||||||
|
String serverUuid,
|
||||||
SignalServiceContentProto serializedState)
|
SignalServiceContentProto serializedState)
|
||||||
{
|
{
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -139,6 +145,7 @@ public final class SignalServiceContent {
|
||||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
this.needsReceipt = needsReceipt;
|
this.needsReceipt = needsReceipt;
|
||||||
|
this.serverUuid = serverUuid;
|
||||||
this.serializedState = serializedState;
|
this.serializedState = serializedState;
|
||||||
|
|
||||||
this.message = Optional.absent();
|
this.message = Optional.absent();
|
||||||
|
@ -155,6 +162,7 @@ public final class SignalServiceContent {
|
||||||
long serverReceivedTimestamp,
|
long serverReceivedTimestamp,
|
||||||
long serverDeliveredTimestamp,
|
long serverDeliveredTimestamp,
|
||||||
boolean needsReceipt,
|
boolean needsReceipt,
|
||||||
|
String serverUuid,
|
||||||
SignalServiceContentProto serializedState)
|
SignalServiceContentProto serializedState)
|
||||||
{
|
{
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -163,6 +171,7 @@ public final class SignalServiceContent {
|
||||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
this.needsReceipt = needsReceipt;
|
this.needsReceipt = needsReceipt;
|
||||||
|
this.serverUuid = serverUuid;
|
||||||
this.serializedState = serializedState;
|
this.serializedState = serializedState;
|
||||||
|
|
||||||
this.message = Optional.absent();
|
this.message = Optional.absent();
|
||||||
|
@ -179,6 +188,7 @@ public final class SignalServiceContent {
|
||||||
long serverReceivedTimestamp,
|
long serverReceivedTimestamp,
|
||||||
long serverDeliveredTimestamp,
|
long serverDeliveredTimestamp,
|
||||||
boolean needsReceipt,
|
boolean needsReceipt,
|
||||||
|
String serverUuid,
|
||||||
SignalServiceContentProto serializedState)
|
SignalServiceContentProto serializedState)
|
||||||
{
|
{
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
@ -187,6 +197,7 @@ public final class SignalServiceContent {
|
||||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
this.needsReceipt = needsReceipt;
|
this.needsReceipt = needsReceipt;
|
||||||
|
this.serverUuid = serverUuid;
|
||||||
this.serializedState = serializedState;
|
this.serializedState = serializedState;
|
||||||
|
|
||||||
this.message = Optional.absent();
|
this.message = Optional.absent();
|
||||||
|
@ -240,6 +251,10 @@ public final class SignalServiceContent {
|
||||||
return needsReceipt;
|
return needsReceipt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getServerUuid() {
|
||||||
|
return serverUuid;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] serialize() {
|
public byte[] serialize() {
|
||||||
return serializedState.toByteArray();
|
return serializedState.toByteArray();
|
||||||
}
|
}
|
||||||
|
@ -276,6 +291,7 @@ public final class SignalServiceContent {
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
metadata.isNeedsReceipt(),
|
metadata.isNeedsReceipt(),
|
||||||
|
metadata.getServerGuid(),
|
||||||
serviceContentProto);
|
serviceContentProto);
|
||||||
} else if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.CONTENT) {
|
} else if (serviceContentProto.getDataCase() == SignalServiceContentProto.DataCase.CONTENT) {
|
||||||
SignalServiceProtos.Content message = serviceContentProto.getContent();
|
SignalServiceProtos.Content message = serviceContentProto.getContent();
|
||||||
|
@ -288,6 +304,7 @@ public final class SignalServiceContent {
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
metadata.isNeedsReceipt(),
|
metadata.isNeedsReceipt(),
|
||||||
|
metadata.getServerGuid(),
|
||||||
serviceContentProto);
|
serviceContentProto);
|
||||||
} else if (message.hasSyncMessage() && localAddress.matches(metadata.getSender())) {
|
} else if (message.hasSyncMessage() && localAddress.matches(metadata.getSender())) {
|
||||||
return new SignalServiceContent(createSynchronizeMessage(metadata, message.getSyncMessage()),
|
return new SignalServiceContent(createSynchronizeMessage(metadata, message.getSyncMessage()),
|
||||||
|
@ -297,6 +314,7 @@ public final class SignalServiceContent {
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
metadata.isNeedsReceipt(),
|
metadata.isNeedsReceipt(),
|
||||||
|
metadata.getServerGuid(),
|
||||||
serviceContentProto);
|
serviceContentProto);
|
||||||
} else if (message.hasCallMessage()) {
|
} else if (message.hasCallMessage()) {
|
||||||
return new SignalServiceContent(createCallMessage(message.getCallMessage()),
|
return new SignalServiceContent(createCallMessage(message.getCallMessage()),
|
||||||
|
@ -306,6 +324,7 @@ public final class SignalServiceContent {
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
metadata.isNeedsReceipt(),
|
metadata.isNeedsReceipt(),
|
||||||
|
metadata.getServerGuid(),
|
||||||
serviceContentProto);
|
serviceContentProto);
|
||||||
} else if (message.hasReceiptMessage()) {
|
} else if (message.hasReceiptMessage()) {
|
||||||
return new SignalServiceContent(createReceiptMessage(metadata, message.getReceiptMessage()),
|
return new SignalServiceContent(createReceiptMessage(metadata, message.getReceiptMessage()),
|
||||||
|
@ -315,6 +334,7 @@ public final class SignalServiceContent {
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
metadata.isNeedsReceipt(),
|
metadata.isNeedsReceipt(),
|
||||||
|
metadata.getServerGuid(),
|
||||||
serviceContentProto);
|
serviceContentProto);
|
||||||
} else if (message.hasTypingMessage()) {
|
} else if (message.hasTypingMessage()) {
|
||||||
return new SignalServiceContent(createTypingMessage(metadata, message.getTypingMessage()),
|
return new SignalServiceContent(createTypingMessage(metadata, message.getTypingMessage()),
|
||||||
|
@ -324,6 +344,7 @@ public final class SignalServiceContent {
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
false,
|
false,
|
||||||
|
metadata.getServerGuid(),
|
||||||
serviceContentProto);
|
serviceContentProto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,29 +9,14 @@ package org.whispersystems.signalservice.api.messages;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
import org.whispersystems.libsignal.InvalidVersionException;
|
|
||||||
import org.whispersystems.libsignal.logging.Log;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope;
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope;
|
||||||
import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceEnvelopeProto;
|
import org.whispersystems.signalservice.internal.serialize.protos.SignalServiceEnvelopeProto;
|
||||||
import org.whispersystems.signalservice.internal.util.Hex;
|
|
||||||
import org.whispersystems.util.Base64;
|
import org.whispersystems.util.Base64;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
import javax.crypto.Mac;
|
|
||||||
import javax.crypto.NoSuchPaddingException;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents an encrypted Signal Service envelope.
|
* This class represents an encrypted Signal Service envelope.
|
||||||
|
@ -129,11 +114,11 @@ public class SignalServiceEnvelope {
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUuid() {
|
public String getServerGuid() {
|
||||||
return envelope.getServerGuid();
|
return envelope.getServerGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasUuid() {
|
public boolean hasServerGuid() {
|
||||||
return envelope.hasServerGuid();
|
return envelope.hasServerGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +270,8 @@ public class SignalServiceEnvelope {
|
||||||
builder.setContent(ByteString.copyFrom(getContent()));
|
builder.setContent(ByteString.copyFrom(getContent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUuid()) {
|
if (hasServerGuid()) {
|
||||||
builder.setServerGuid(getUuid());
|
builder.setServerGuid(getServerGuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build().toByteArray();
|
return builder.build().toByteArray();
|
||||||
|
|
|
@ -9,13 +9,15 @@ public final class SignalServiceMetadata {
|
||||||
private final long serverReceivedTimestamp;
|
private final long serverReceivedTimestamp;
|
||||||
private final long serverDeliveredTimestamp;
|
private final long serverDeliveredTimestamp;
|
||||||
private final boolean needsReceipt;
|
private final boolean needsReceipt;
|
||||||
|
private final String serverGuid;
|
||||||
|
|
||||||
public SignalServiceMetadata(SignalServiceAddress sender,
|
public SignalServiceMetadata(SignalServiceAddress sender,
|
||||||
int senderDevice,
|
int senderDevice,
|
||||||
long timestamp,
|
long timestamp,
|
||||||
long serverReceivedTimestamp,
|
long serverReceivedTimestamp,
|
||||||
long serverDeliveredTimestamp,
|
long serverDeliveredTimestamp,
|
||||||
boolean needsReceipt)
|
boolean needsReceipt,
|
||||||
|
String serverGuid)
|
||||||
{
|
{
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.senderDevice = senderDevice;
|
this.senderDevice = senderDevice;
|
||||||
|
@ -23,6 +25,7 @@ public final class SignalServiceMetadata {
|
||||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||||
this.needsReceipt = needsReceipt;
|
this.needsReceipt = needsReceipt;
|
||||||
|
this.serverGuid = serverGuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignalServiceAddress getSender() {
|
public SignalServiceAddress getSender() {
|
||||||
|
@ -48,4 +51,8 @@ public final class SignalServiceMetadata {
|
||||||
public boolean isNeedsReceipt() {
|
public boolean isNeedsReceipt() {
|
||||||
return needsReceipt;
|
return needsReceipt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getServerGuid() {
|
||||||
|
return serverGuid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,8 @@ public class PushServiceSocket {
|
||||||
private static final String SUBMIT_RATE_LIMIT_CHALLENGE = "/v1/challenge";
|
private static final String SUBMIT_RATE_LIMIT_CHALLENGE = "/v1/challenge";
|
||||||
private static final String REQUEST_RATE_LIMIT_PUSH_CHALLENGE = "/v1/challenge/push";
|
private static final String REQUEST_RATE_LIMIT_PUSH_CHALLENGE = "/v1/challenge/push";
|
||||||
|
|
||||||
|
private static final String REPORT_SPAM = "/v1/messages/report/%s/%s";
|
||||||
|
|
||||||
private static final String SERVER_DELIVERED_TIMESTAMP_HEADER = "X-Signal-Timestamp";
|
private static final String SERVER_DELIVERED_TIMESTAMP_HEADER = "X-Signal-Timestamp";
|
||||||
|
|
||||||
private static final Map<String, String> NO_HEADERS = Collections.emptyMap();
|
private static final Map<String, String> NO_HEADERS = Collections.emptyMap();
|
||||||
|
@ -1500,7 +1502,7 @@ public class PushServiceSocket {
|
||||||
throw new ServerRejectedException();
|
throw new ServerRejectedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseCode != 200 && responseCode != 204) {
|
if (responseCode != 200 && responseCode != 202 && responseCode != 204) {
|
||||||
throw new NonSuccessfulResponseCodeException(responseCode, "Bad response: " + responseCode + " " + responseMessage);
|
throw new NonSuccessfulResponseCodeException(responseCode, "Bad response: " + responseCode + " " + responseMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2188,6 +2190,12 @@ public class PushServiceSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reportSpam(String e164, String serverGuid)
|
||||||
|
throws NonSuccessfulResponseCodeException, MalformedResponseException, PushNetworkException
|
||||||
|
{
|
||||||
|
makeServiceRequest(String.format(REPORT_SPAM, e164, serverGuid), "POST", "");
|
||||||
|
}
|
||||||
|
|
||||||
public static final class GroupHistory {
|
public static final class GroupHistory {
|
||||||
private final GroupChanges groupChanges;
|
private final GroupChanges groupChanges;
|
||||||
private final Optional<ContentRange> contentRange;
|
private final Optional<ContentRange> contentRange;
|
||||||
|
|
|
@ -16,15 +16,17 @@ public final class SignalServiceMetadataProtobufSerializer {
|
||||||
.setTimestamp(metadata.getTimestamp())
|
.setTimestamp(metadata.getTimestamp())
|
||||||
.setServerReceivedTimestamp(metadata.getServerReceivedTimestamp())
|
.setServerReceivedTimestamp(metadata.getServerReceivedTimestamp())
|
||||||
.setServerDeliveredTimestamp(metadata.getServerDeliveredTimestamp())
|
.setServerDeliveredTimestamp(metadata.getServerDeliveredTimestamp())
|
||||||
|
.setServerGuid(metadata.getServerGuid())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SignalServiceMetadata fromProtobuf(MetadataProto metadata) {
|
public static SignalServiceMetadata fromProtobuf(MetadataProto metadata) {
|
||||||
return new SignalServiceMetadata(SignalServiceAddressProtobufSerializer.fromProtobuf(metadata.getAddress()),
|
return new SignalServiceMetadata(SignalServiceAddressProtobufSerializer.fromProtobuf(metadata.getAddress()),
|
||||||
metadata.getSenderDevice(),
|
metadata.getSenderDevice(),
|
||||||
metadata.getTimestamp(),
|
metadata.getTimestamp(),
|
||||||
metadata.getServerReceivedTimestamp(),
|
metadata.getServerReceivedTimestamp(),
|
||||||
metadata.getServerDeliveredTimestamp(),
|
metadata.getServerDeliveredTimestamp(),
|
||||||
metadata.getNeedsReceipt());
|
metadata.getNeedsReceipt(),
|
||||||
|
metadata.getServerGuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ message MetadataProto {
|
||||||
optional int64 serverReceivedTimestamp = 5;
|
optional int64 serverReceivedTimestamp = 5;
|
||||||
optional int64 serverDeliveredTimestamp = 6;
|
optional int64 serverDeliveredTimestamp = 6;
|
||||||
optional bool needsReceipt = 4;
|
optional bool needsReceipt = 4;
|
||||||
|
optional string serverGuid = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddressProto {
|
message AddressProto {
|
||||||
|
|
Ładowanie…
Reference in New Issue