mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 09:20:19 +01:00
Handle 428 rate limiting.
This commit is contained in:
@@ -89,6 +89,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||
public abstract @Nullable ViewOnceExpirationInfo getNearestExpiringViewOnceMessage();
|
||||
public abstract boolean isSent(long messageId);
|
||||
public abstract List<MessageRecord> getProfileChangeDetailsRecords(long threadId, long afterTimestamp);
|
||||
public abstract Set<Long> getAllRateLimitedMessageIds();
|
||||
|
||||
public abstract void markExpireStarted(long messageId);
|
||||
public abstract void markExpireStarted(long messageId, long startTime);
|
||||
@@ -101,6 +102,8 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||
public abstract void markAsInsecure(long id);
|
||||
public abstract void markAsPush(long id);
|
||||
public abstract void markAsForcedSms(long id);
|
||||
public abstract void markAsRateLimited(long id);
|
||||
public abstract void clearRateLimitStatus(Collection<Long> ids);
|
||||
public abstract void markAsDecryptFailed(long id);
|
||||
public abstract void markAsDecryptDuplicate(long id);
|
||||
public abstract void markAsNoSession(long id);
|
||||
|
||||
@@ -785,6 +785,30 @@ public class MmsDatabase extends MessageDatabase {
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsRateLimited(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
updateMailboxBitmask(messageId, 0, Types.MESSAGE_RATE_LIMITED_BIT, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRateLimitStatus(@NonNull Collection<Long> ids) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (long id : ids) {
|
||||
long threadId = getThreadIdForMessage(id);
|
||||
updateMailboxBitmask(id, Types.MESSAGE_RATE_LIMITED_BIT, 0, Optional.of(threadId));
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsPendingInsecureSmsFallback(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
@@ -1708,6 +1732,22 @@ public class MmsDatabase extends MessageDatabase {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> getAllRateLimitedMessageIds() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = "(" + MESSAGE_BOX + " & " + Types.TOTAL_MASK + " & " + Types.MESSAGE_RATE_LIMITED_BIT + ") > 0";
|
||||
|
||||
Set<Long> ids = new HashSet<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID }, where, null, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
ids.add(CursorUtil.requireLong(cursor, ID));
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
void deleteThreads(@NonNull Set<Long> threadIds) {
|
||||
Log.d(TAG, "deleteThreads(count: " + threadIds.size() + ")");
|
||||
|
||||
@@ -28,7 +28,34 @@ public interface MmsSmsColumns {
|
||||
public static final String REACTIONS_LAST_SEEN = "reactions_last_seen";
|
||||
public static final String REMOTE_DELETED = "remote_deleted";
|
||||
|
||||
/**
|
||||
* For storage efficiency, all types are stored within a single 64-bit integer column in the
|
||||
* database. There are various areas reserved for different classes of data.
|
||||
*
|
||||
* When carving out a new area, if it's storing a bunch of mutually-exclusive flags (like in
|
||||
* {@link #BASE_TYPE_MASK}, you should store integers in that area. If multiple flags can be set
|
||||
* within a category, you'll have to store them as bits. Just keep in mind that storing as bits
|
||||
* means we can store less data (i.e. 4 bits can store 16 exclusive values, or 4 non-exclusive
|
||||
* values). This was not always followed in the past, and now we've wasted some space.
|
||||
*
|
||||
* Note: We technically could use up to 64 bits, but {@link #TOTAL_MASK} is currently just set to
|
||||
* look at 32. Theoretically if we needed more bits, we could just use them and expand the size of
|
||||
* {@link #TOTAL_MASK}.
|
||||
*
|
||||
* <pre>
|
||||
* _____________________________________ ENCRYPTION ({@link #ENCRYPTION_MASK})
|
||||
* | _____________________________ SECURE MESSAGE INFORMATION (no mask, but look at {@link #SECURE_MESSAGE_BIT})
|
||||
* | | ________________________ GROUPS (no mask, but look at {@link #GROUP_UPDATE_BIT})
|
||||
* | | | _________________ KEY_EXCHANGE ({@link #KEY_EXCHANGE_MASK})
|
||||
* | | | | _________ MESSAGE_ATTRIBUTES ({@link #MESSAGE_ATTRIBUTE_MASK})
|
||||
* | | | | | ____ BASE_TYPE ({@link #BASE_TYPE_MASK})
|
||||
* ___|___ _| _| ___|__ | __|_
|
||||
* | | | | | | | | | || |
|
||||
* 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
* </pre>
|
||||
*/
|
||||
public static class Types {
|
||||
|
||||
protected static final long TOTAL_MASK = 0xFFFFFFFF;
|
||||
|
||||
// Base Types
|
||||
@@ -63,8 +90,10 @@ public interface MmsSmsColumns {
|
||||
OUTGOING_AUDIO_CALL_TYPE, OUTGOING_VIDEO_CALL_TYPE};
|
||||
|
||||
// Message attributes
|
||||
protected static final long MESSAGE_ATTRIBUTE_MASK = 0xE0;
|
||||
protected static final long MESSAGE_FORCE_SMS_BIT = 0x40;
|
||||
protected static final long MESSAGE_ATTRIBUTE_MASK = 0xE0;
|
||||
protected static final long MESSAGE_RATE_LIMITED_BIT = 0x80;
|
||||
protected static final long MESSAGE_FORCE_SMS_BIT = 0x40;
|
||||
// Note: Might be wise to reserve 0x20 -- it would let us expand BASE_MASK by a bit if needed
|
||||
|
||||
// Key Exchange Information
|
||||
protected static final long KEY_EXCHANGE_MASK = 0xFF00;
|
||||
@@ -210,6 +239,10 @@ public interface MmsSmsColumns {
|
||||
return (type & KEY_EXCHANGE_IDENTITY_UPDATE_BIT) != 0;
|
||||
}
|
||||
|
||||
public static boolean isRateLimited(long type) {
|
||||
return (type & MESSAGE_RATE_LIMITED_BIT) != 0;
|
||||
}
|
||||
|
||||
public static boolean isCallLog(long type) {
|
||||
return isIncomingAudioCall(type) ||
|
||||
isIncomingVideoCall(type) ||
|
||||
|
||||
@@ -47,7 +47,6 @@ import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.revealable.ViewOnceExpirationInfo;
|
||||
@@ -321,6 +320,27 @@ public class SmsDatabase extends MessageDatabase {
|
||||
updateTypeBitmask(id, Types.PUSH_MESSAGE_BIT, Types.MESSAGE_FORCE_SMS_BIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsRateLimited(long id) {
|
||||
updateTypeBitmask(id, 0, Types.MESSAGE_RATE_LIMITED_BIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRateLimitStatus(@NonNull Collection<Long> ids) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (long id : ids) {
|
||||
updateTypeBitmask(id, Types.MESSAGE_RATE_LIMITED_BIT, 0);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsDecryptFailed(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
|
||||
@@ -887,6 +907,22 @@ public class SmsDatabase extends MessageDatabase {
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> getAllRateLimitedMessageIds() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
String where = "(" + TYPE + " & " + Types.TOTAL_MASK + " & " + Types.MESSAGE_RATE_LIMITED_BIT + ") > 0";
|
||||
|
||||
Set<Long> ids = new HashSet<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] { ID }, where, null, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
ids.add(CursorUtil.requireLong(cursor, ID));
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MessageRecord> getProfileChangeDetailsRecords(long threadId, long afterTimestamp) {
|
||||
String where = THREAD_ID + " = ? AND " + DATE_RECEIVED + " >= ? AND " + TYPE + " = ?";
|
||||
|
||||
@@ -423,6 +423,10 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return SmsDatabase.Types.isContentBundleKeyExchange(type);
|
||||
}
|
||||
|
||||
public boolean isRateLimited() {
|
||||
return SmsDatabase.Types.isRateLimited(type);
|
||||
}
|
||||
|
||||
public boolean isIdentityUpdate() {
|
||||
return SmsDatabase.Types.isIdentityUpdate(type);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user