mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
RemoteWipeManager WIP
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
package org.briarproject.briar.api.remotewipe;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.ClientId;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface RemoteWipeManager extends ConversationManager.ConversationClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique ID of the remote wipe client.
|
||||||
|
*/
|
||||||
|
ClientId CLIENT_ID = new ClientId("pw.darkcrystal.remotewipe");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current major version of the remote wipe client.
|
||||||
|
*/
|
||||||
|
int MAJOR_VERSION = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current minor version of the remote wipe client.
|
||||||
|
*/
|
||||||
|
int MINOR_VERSION = 0;
|
||||||
|
|
||||||
|
void setup(Transaction txn, List<ContactId> wipers)
|
||||||
|
throws DbException, FormatException;
|
||||||
|
|
||||||
|
void wipe(Transaction txn, Contact contact)
|
||||||
|
throws DbException, FormatException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Collection<ConversationMessageHeader> getMessageHeaders(
|
||||||
|
Transaction txn, ContactId contactId) throws DbException;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.briarproject.briar.remotewipe;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
enum MessageType {
|
||||||
|
|
||||||
|
SETUP(0), WIPE(1);
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
MessageType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MessageType fromValue(int value) throws
|
||||||
|
FormatException {
|
||||||
|
for (MessageType m : values()) if (m.value == value) return m;
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
package org.briarproject.briar.remotewipe;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
|
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.bramble.api.data.BdfEntry;
|
||||||
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
|
import org.briarproject.bramble.api.data.MetadataParser;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.briar.api.attachment.AttachmentHeader;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
|
import org.briarproject.briar.api.conversation.DeletionResult;
|
||||||
|
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
|
||||||
|
import org.briarproject.briar.client.ConversationClientImpl;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
|
||||||
|
import static org.briarproject.briar.remotewipe.MessageType.SETUP;
|
||||||
|
import static org.briarproject.briar.remotewipe.MessageType.WIPE;
|
||||||
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.GROUP_KEY_CONTACT_ID;
|
||||||
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_LOCAL;
|
||||||
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_MESSAGE_TYPE;
|
||||||
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_TIMESTAMP;
|
||||||
|
|
||||||
|
public class RemoteWipeManagerImpl extends ConversationClientImpl
|
||||||
|
implements RemoteWipeManager, LifecycleManager.OpenDatabaseHook {
|
||||||
|
|
||||||
|
private final Group localGroup;
|
||||||
|
private final Clock clock;
|
||||||
|
private final ContactGroupFactory contactGroupFactory;
|
||||||
|
private final ContactManager contactManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected RemoteWipeManagerImpl(
|
||||||
|
DatabaseComponent db,
|
||||||
|
ClientHelper clientHelper,
|
||||||
|
MetadataParser metadataParser,
|
||||||
|
MessageTracker messageTracker,
|
||||||
|
Clock clock,
|
||||||
|
ContactManager contactManager,
|
||||||
|
ContactGroupFactory contactGroupFactory) {
|
||||||
|
super(db, clientHelper, metadataParser, messageTracker);
|
||||||
|
this.clock = clock;
|
||||||
|
this.contactGroupFactory = contactGroupFactory;
|
||||||
|
this.contactManager = contactManager;
|
||||||
|
localGroup =
|
||||||
|
contactGroupFactory.createLocalGroup(CLIENT_ID, MAJOR_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||||
|
BdfDictionary meta) throws DbException, FormatException {
|
||||||
|
|
||||||
|
MessageType type = MessageType.fromValue(body.getLong(0).intValue());
|
||||||
|
if (type == SETUP) {
|
||||||
|
|
||||||
|
|
||||||
|
messageTracker.trackIncomingMessage(txn, m);
|
||||||
|
// message.getGroupId turn into contactid
|
||||||
|
// txn.attach event
|
||||||
|
} else if (type == WIPE) {
|
||||||
|
|
||||||
|
ContactId contactId = getContactId(txn, m.getGroupId());
|
||||||
|
// check if contact is in list of wipers
|
||||||
|
// if so, increment counter
|
||||||
|
// check if counter = threshold
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setup(Transaction txn, List<ContactId> wipers)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
// TODO if (we already have a set of wipers?) do something
|
||||||
|
if (wipers.size() < 2) throw new FormatException();
|
||||||
|
for (ContactId c : wipers) {
|
||||||
|
sendSetupMessage(txn, contactManager.getContact(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Make some sort of record of this
|
||||||
|
// clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendSetupMessage(Transaction txn, Contact contact)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
Group group = getContactGroup(contact);
|
||||||
|
GroupId g = group.getId();
|
||||||
|
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
|
||||||
|
long timestamp = clock.currentTimeMillis();
|
||||||
|
|
||||||
|
byte[] body = "setup message".getBytes(); // TODO
|
||||||
|
|
||||||
|
Message m = clientHelper.createMessage(g, timestamp, body);
|
||||||
|
// TODO remote-wipe versions of MESSAGE_KEY
|
||||||
|
BdfDictionary meta = BdfDictionary.of(
|
||||||
|
new BdfEntry(MSG_KEY_MESSAGE_TYPE, SETUP.getValue()),
|
||||||
|
new BdfEntry(MSG_KEY_LOCAL, true),
|
||||||
|
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
|
||||||
|
);
|
||||||
|
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
||||||
|
messageTracker.trackOutgoingMessage(txn, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void wipe(Transaction txn, Contact contact)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
// TODO check that we have a SETUP message from contact
|
||||||
|
Group group = getContactGroup(contact);
|
||||||
|
GroupId g = group.getId();
|
||||||
|
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
|
||||||
|
long timestamp = clock.currentTimeMillis();
|
||||||
|
|
||||||
|
byte[] body = "wipe message".getBytes(); // TODO
|
||||||
|
|
||||||
|
Message m = clientHelper.createMessage(g, timestamp, body);
|
||||||
|
// TODO remote-wipe versions of MESSAGE_KEY
|
||||||
|
BdfDictionary meta = BdfDictionary.of(
|
||||||
|
new BdfEntry(MSG_KEY_MESSAGE_TYPE, SETUP.getValue()),
|
||||||
|
new BdfEntry(MSG_KEY_LOCAL, true),
|
||||||
|
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
|
||||||
|
);
|
||||||
|
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
||||||
|
messageTracker.trackOutgoingMessage(txn, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDatabaseOpened(Transaction txn) throws DbException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Group getContactGroup(Contact c) {
|
||||||
|
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
||||||
|
MAJOR_VERSION, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ConversationMessageHeader> getMessageHeaders(
|
||||||
|
Transaction txn, ContactId contactId) throws DbException {
|
||||||
|
try {
|
||||||
|
Contact contact = db.getContact(txn, contactId);
|
||||||
|
GroupId contactGroupId = getContactGroup(contact).getId();
|
||||||
|
Map<MessageId, BdfDictionary> messages = clientHelper
|
||||||
|
.getMessageMetadataAsDictionary(txn, contactGroupId);
|
||||||
|
List<ConversationMessageHeader> headers =
|
||||||
|
new ArrayList<>();
|
||||||
|
for (Map.Entry<MessageId, BdfDictionary> messageEntry : messages
|
||||||
|
.entrySet()) {
|
||||||
|
BdfDictionary meta = messageEntry.getValue();
|
||||||
|
if (meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue() ==
|
||||||
|
SETUP.getValue()) {
|
||||||
|
Message message = clientHelper
|
||||||
|
.getMessage(txn, messageEntry.getKey());
|
||||||
|
MessageStatus status = db.getMessageStatus(txn, contactId,
|
||||||
|
messageEntry.getKey());
|
||||||
|
headers.add(
|
||||||
|
createSetupMessageHeader(message, meta, status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO create a SetupMessageHeader
|
||||||
|
private ShardMessageHeader createSetupMessageHeader(
|
||||||
|
Message message, BdfDictionary meta, MessageStatus status
|
||||||
|
)
|
||||||
|
throws FormatException {
|
||||||
|
|
||||||
|
boolean isLocal = meta.getBoolean(MSG_KEY_LOCAL);
|
||||||
|
boolean read = meta.getBoolean(MSG_KEY_READ, false);
|
||||||
|
long timestamp;
|
||||||
|
if (isLocal) {
|
||||||
|
timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
|
||||||
|
} else {
|
||||||
|
timestamp = message.getTimestamp();
|
||||||
|
}
|
||||||
|
List<AttachmentHeader> attachmentHeaders =
|
||||||
|
new ArrayList<>();
|
||||||
|
return new ShardMessageHeader(
|
||||||
|
message.getId(), message.getGroupId(), timestamp,
|
||||||
|
isLocal, read, status.isSent(), status.isSeen(),
|
||||||
|
attachmentHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<MessageId> getMessageIds(Transaction txn, ContactId contactId)
|
||||||
|
throws DbException {
|
||||||
|
Contact contact = db.getContact(txn, contactId);
|
||||||
|
GroupId contactGroupId = getContactGroup(contact).getId();
|
||||||
|
try {
|
||||||
|
Map<MessageId, BdfDictionary> messages = clientHelper
|
||||||
|
.getMessageMetadataAsDictionary(txn, contactGroupId);
|
||||||
|
return messages.keySet();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeletionResult deleteAllMessages(Transaction txn, ContactId c)
|
||||||
|
throws DbException {
|
||||||
|
DeletionResult result = new DeletionResult();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeletionResult deleteMessages(Transaction txn, ContactId c,
|
||||||
|
Set<MessageId> messageIds) throws DbException {
|
||||||
|
DeletionResult result = new DeletionResult();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContactId getContactId(Transaction txn, GroupId g)
|
||||||
|
throws DbException {
|
||||||
|
try {
|
||||||
|
BdfDictionary meta =
|
||||||
|
clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||||
|
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user