Commit 0224733b authored by ameba23's avatar ameba23
Browse files

RemoteWipeManager WIP

parent 55e0ba88
Pipeline #6614 passed with stages
in 9 minutes and 42 seconds
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;
}
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();
}
}
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);
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment