mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
218 lines
7.1 KiB
Java
218 lines
7.1 KiB
Java
package org.briarproject.android.privategroup.creation;
|
|
|
|
import org.briarproject.android.controller.DbControllerImpl;
|
|
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
|
import org.briarproject.api.contact.Contact;
|
|
import org.briarproject.api.contact.ContactId;
|
|
import org.briarproject.api.contact.ContactManager;
|
|
import org.briarproject.api.crypto.CryptoExecutor;
|
|
import org.briarproject.api.db.DatabaseExecutor;
|
|
import org.briarproject.api.db.DbException;
|
|
import org.briarproject.api.db.NoSuchContactException;
|
|
import org.briarproject.api.identity.IdentityManager;
|
|
import org.briarproject.api.identity.LocalAuthor;
|
|
import org.briarproject.api.lifecycle.LifecycleManager;
|
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
|
import org.briarproject.api.privategroup.GroupMessage;
|
|
import org.briarproject.api.privategroup.GroupMessageFactory;
|
|
import org.briarproject.api.privategroup.PrivateGroup;
|
|
import org.briarproject.api.privategroup.PrivateGroupFactory;
|
|
import org.briarproject.api.privategroup.PrivateGroupManager;
|
|
import org.briarproject.api.privategroup.invitation.GroupInvitationFactory;
|
|
import org.briarproject.api.privategroup.invitation.GroupInvitationManager;
|
|
import org.briarproject.api.sync.GroupId;
|
|
import org.briarproject.api.system.Clock;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.annotation.concurrent.Immutable;
|
|
import javax.inject.Inject;
|
|
|
|
import static java.util.logging.Level.WARNING;
|
|
|
|
@Immutable
|
|
@NotNullByDefault
|
|
public class CreateGroupControllerImpl extends DbControllerImpl
|
|
implements CreateGroupController {
|
|
|
|
private static final Logger LOG =
|
|
Logger.getLogger(CreateGroupControllerImpl.class.getName());
|
|
|
|
private final Executor cryptoExecutor;
|
|
private final ContactManager contactManager;
|
|
private final IdentityManager identityManager;
|
|
private final PrivateGroupFactory groupFactory;
|
|
private final GroupMessageFactory groupMessageFactory;
|
|
private final PrivateGroupManager groupManager;
|
|
private final GroupInvitationFactory groupInvitationFactory;
|
|
private final GroupInvitationManager groupInvitationManager;
|
|
private final Clock clock;
|
|
|
|
@Inject
|
|
CreateGroupControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
|
@CryptoExecutor Executor cryptoExecutor,
|
|
LifecycleManager lifecycleManager, ContactManager contactManager,
|
|
IdentityManager identityManager, PrivateGroupFactory groupFactory,
|
|
GroupMessageFactory groupMessageFactory,
|
|
PrivateGroupManager groupManager,
|
|
GroupInvitationFactory groupInvitationFactory,
|
|
GroupInvitationManager groupInvitationManager, Clock clock) {
|
|
super(dbExecutor, lifecycleManager);
|
|
this.cryptoExecutor = cryptoExecutor;
|
|
this.contactManager = contactManager;
|
|
this.identityManager = identityManager;
|
|
this.groupFactory = groupFactory;
|
|
this.groupMessageFactory = groupMessageFactory;
|
|
this.groupManager = groupManager;
|
|
this.groupInvitationFactory = groupInvitationFactory;
|
|
this.groupInvitationManager = groupInvitationManager;
|
|
this.clock = clock;
|
|
}
|
|
|
|
@Override
|
|
public void createGroup(final String name,
|
|
final ResultExceptionHandler<GroupId, DbException> handler) {
|
|
runOnDbThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
LocalAuthor author = identityManager.getLocalAuthor();
|
|
createGroupAndMessages(author, name, handler);
|
|
} catch (DbException e) {
|
|
if (LOG.isLoggable(WARNING))
|
|
LOG.log(WARNING, e.toString(), e);
|
|
handler.onException(e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void createGroupAndMessages(final LocalAuthor author,
|
|
final String name,
|
|
final ResultExceptionHandler<GroupId, DbException> handler) {
|
|
cryptoExecutor.execute(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
LOG.info("Creating group...");
|
|
PrivateGroup group =
|
|
groupFactory.createPrivateGroup(name, author);
|
|
LOG.info("Creating new join announcement...");
|
|
GroupMessage joinMsg = groupMessageFactory
|
|
.createJoinMessage(group.getId(),
|
|
clock.currentTimeMillis(), author);
|
|
storeGroup(group, joinMsg, handler);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void storeGroup(final PrivateGroup group,
|
|
final GroupMessage joinMsg,
|
|
final ResultExceptionHandler<GroupId, DbException> handler) {
|
|
runOnDbThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
LOG.info("Adding group to database...");
|
|
try {
|
|
groupManager.addPrivateGroup(group, joinMsg);
|
|
handler.onResult(group.getId());
|
|
} catch (DbException e) {
|
|
if (LOG.isLoggable(WARNING))
|
|
LOG.log(WARNING, e.toString(), e);
|
|
handler.onException(e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void sendInvitation(final GroupId g,
|
|
final Collection<ContactId> contactIds, final String message,
|
|
final ResultExceptionHandler<Void, DbException> handler) {
|
|
runOnDbThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
LocalAuthor localAuthor = identityManager.getLocalAuthor();
|
|
List<Contact> contacts = new ArrayList<>();
|
|
for (ContactId c : contactIds) {
|
|
try {
|
|
contacts.add(contactManager.getContact(c));
|
|
} catch (NoSuchContactException e) {
|
|
// Continue
|
|
}
|
|
}
|
|
signInvitations(g, localAuthor, contacts, message, handler);
|
|
} catch (DbException e) {
|
|
if (LOG.isLoggable(WARNING))
|
|
LOG.log(WARNING, e.toString(), e);
|
|
handler.onException(e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void signInvitations(final GroupId g, final LocalAuthor localAuthor,
|
|
final Collection<Contact> contacts, final String message,
|
|
final ResultExceptionHandler<Void, DbException> handler) {
|
|
cryptoExecutor.execute(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
long timestamp = clock.currentTimeMillis();
|
|
List<InvitationContext> contexts = new ArrayList<>();
|
|
for (Contact c : contacts) {
|
|
byte[] signature = groupInvitationFactory.signInvitation(c,
|
|
g, timestamp, localAuthor.getPrivateKey());
|
|
contexts.add(new InvitationContext(c.getId(), timestamp,
|
|
signature));
|
|
}
|
|
sendInvitations(g, contexts, message, handler);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void sendInvitations(final GroupId g,
|
|
final Collection<InvitationContext> contexts, final String message,
|
|
final ResultExceptionHandler<Void, DbException> handler) {
|
|
runOnDbThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
String msg = message.isEmpty() ? null : message;
|
|
for (InvitationContext context : contexts) {
|
|
try {
|
|
groupInvitationManager.sendInvitation(g,
|
|
context.contactId, msg, context.timestamp,
|
|
context.signature);
|
|
} catch (NoSuchContactException e) {
|
|
// Continue
|
|
}
|
|
}
|
|
handler.onResult(null);
|
|
} catch (DbException e) {
|
|
if (LOG.isLoggable(WARNING))
|
|
LOG.log(WARNING, e.toString(), e);
|
|
handler.onException(e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private static class InvitationContext {
|
|
|
|
private final ContactId contactId;
|
|
private final long timestamp;
|
|
private final byte[] signature;
|
|
|
|
private InvitationContext(ContactId contactId, long timestamp,
|
|
byte[] signature) {
|
|
this.contactId = contactId;
|
|
this.timestamp = timestamp;
|
|
this.signature = signature;
|
|
}
|
|
}
|
|
}
|