diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index bdd7e6691a3050e536de1e373354c2d517166814..45ef3b96063731c024375a8745646802eb2a011a 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -157,6 +157,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { T txn = unbox(transaction); if (!db.containsLocalAuthor(txn, local)) throw new NoSuchLocalAuthorException(); + if (db.containsLocalAuthor(txn, remote.getId())) + throw new ContactExistsException(); if (db.containsContact(txn, remote.getId(), local)) throw new ContactExistsException(); ContactId c = db.addContact(txn, remote, local, active); diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java index 034de653164d6ed5ac3e3e9c09bd7e0697fbe8f2..97b08d900f5936118a5ea410019bcbec0a9976a9 100644 --- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java +++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java @@ -6,6 +6,7 @@ import org.briarproject.api.TransportId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.db.ContactExistsException; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.Metadata; import org.briarproject.api.db.NoSuchContactException; @@ -143,6 +144,8 @@ public class DatabaseComponentImplTest extends BriarTestCase { // addContact() oneOf(database).containsLocalAuthor(txn, localAuthorId); will(returnValue(true)); + oneOf(database).containsLocalAuthor(txn, authorId); + will(returnValue(false)); oneOf(database).containsContact(txn, authorId, localAuthorId); will(returnValue(false)); oneOf(database).addContact(txn, author, localAuthorId, true); @@ -767,6 +770,8 @@ public class DatabaseComponentImplTest extends BriarTestCase { // addContact() oneOf(database).containsLocalAuthor(txn, localAuthorId); will(returnValue(true)); + oneOf(database).containsLocalAuthor(txn, authorId); + will(returnValue(false)); oneOf(database).containsContact(txn, authorId, localAuthorId); will(returnValue(false)); oneOf(database).addContact(txn, author, localAuthorId, true); @@ -1484,7 +1489,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { context.checking(new Expectations() {{ oneOf(database).startTransaction(); - will(returnValue(new Object())); + will(returnValue(txn)); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, @@ -1493,8 +1498,81 @@ public class DatabaseComponentImplTest extends BriarTestCase { assertNotNull(db.startTransaction(firstTxnReadOnly)); try { db.startTransaction(secondTxnReadOnly); + fail(); } finally { context.assertIsSatisfied(); } } + + @Test + public void testCannotAddLocalIdentityAsContact() throws Exception { + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database<Object> database = context.mock(Database.class); + final ShutdownManager shutdown = context.mock(ShutdownManager.class); + final EventBus eventBus = context.mock(EventBus.class); + + context.checking(new Expectations() {{ + oneOf(database).startTransaction(); + will(returnValue(txn)); + oneOf(database).containsLocalAuthor(txn, localAuthorId); + will(returnValue(true)); + // Contact is a local identity + oneOf(database).containsLocalAuthor(txn, authorId); + will(returnValue(true)); + oneOf(database).abortTransaction(txn); + }}); + + DatabaseComponent db = createDatabaseComponent(database, eventBus, + shutdown); + + Transaction transaction = db.startTransaction(false); + try { + db.addContact(transaction, author, localAuthorId, true); + fail(); + } catch (ContactExistsException expected) { + // Expected + } finally { + db.endTransaction(transaction); + } + + context.assertIsSatisfied(); + } + + @Test + public void testCannotAddDuplicateContact() throws Exception { + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database<Object> database = context.mock(Database.class); + final ShutdownManager shutdown = context.mock(ShutdownManager.class); + final EventBus eventBus = context.mock(EventBus.class); + + context.checking(new Expectations() {{ + oneOf(database).startTransaction(); + will(returnValue(txn)); + oneOf(database).containsLocalAuthor(txn, localAuthorId); + will(returnValue(true)); + oneOf(database).containsLocalAuthor(txn, authorId); + will(returnValue(false)); + // Contact already exists for this local identity + oneOf(database).containsContact(txn, authorId, localAuthorId); + will(returnValue(true)); + oneOf(database).abortTransaction(txn); + }}); + + DatabaseComponent db = createDatabaseComponent(database, eventBus, + shutdown); + + Transaction transaction = db.startTransaction(false); + try { + db.addContact(transaction, author, localAuthorId, true); + fail(); + } catch (ContactExistsException expected) { + // Expected + } finally { + db.endTransaction(transaction); + } + + context.assertIsSatisfied(); + } }