diff --git a/briar-android/res/layout/list_item_introduction_in.xml b/briar-android/res/layout/list_item_introduction_in.xml index 5daea060852a74a324f23c79cd851ad1fee3ea7a..2f157fad66a360fa76a8a312f8ec88b671c65447 100644 --- a/briar-android/res/layout/list_item_introduction_in.xml +++ b/briar-android/res/layout/list_item_introduction_in.xml @@ -36,7 +36,7 @@ android:layout_marginTop="@dimen/message_bubble_timestamp_margin" android:layout_alignEnd="@+id/introductionText" android:layout_alignRight="@+id/introductionText" - android:layout_below="@+id/acceptButton" + android:layout_below="@+id/declineButton" android:textColor="@color/private_message_date" android:textSize="@dimen/text_size_tiny" tools:text="Dec 24, 13:37"/> @@ -46,7 +46,6 @@ style="@style/BriarButtonFlat.Positive" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="-15dp" android:layout_alignEnd="@+id/introductionText" android:layout_alignRight="@+id/introductionText" android:layout_below="@+id/introductionText" @@ -57,6 +56,7 @@ style="@style/BriarButtonFlat.Negative" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginBottom="-15dp" android:layout_below="@+id/introductionText" android:layout_toLeftOf="@+id/acceptButton" android:layout_toStartOf="@+id/acceptButton" diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index bfd82ba9f3f31685d8a3ea480a0b6979f9c9d5d8..ca1e962f4e95be6e1de366ec80c8a9edc9252721 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -155,6 +155,7 @@ <string name="introduction_request_sent">You have asked to introduce %1$s to %2$s.</string> <string name="introduction_request_received">%1$s has asked to introduce you to %2$s. Do you want to add %2$s to your contact list?</string> <string name="introduction_request_exists_received">%1$s has asked to introduce you to %2$s, but %2$s is already in your contact list. Since %1$s might not know that, you can still respond:</string> + <string name="introduction_request_for_our_identity_received">%1$s has asked to introduce you to %2$s, but %2$s is one of your other identities. For that reason you cannot accept the introduction:</string> <string name="introduction_request_answered_received">%1$s has asked to introduce you to %2$s.</string> <string name="introduction_response_accepted_sent">You accepted the introduction to %1$s.</string> <string name="introduction_response_declined_sent">You declined the introduction to %1$s.</string> diff --git a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java index 4e8267663be841e7e2e79a404bb3c225d51b673e..3a90e4f9946c34e5ea481f3ff574f3fac0eaa537 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java @@ -261,15 +261,23 @@ class ConversationAdapter extends RecyclerView.Adapter { contactName, ir.getName())); } - ui.acceptButton.setVisibility(View.VISIBLE); - ui.acceptButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - intro.respondToIntroduction(ir.getSessionId(), true); - item.setAnswered(true); - notifyItemChanged(position); - } - }); + if (item.getIntroductionRequest().doesIntroduceOtherIdentity()) { + // don't allow accept when one of our identities is introduced + ui.acceptButton.setVisibility(View.GONE); + ui.text.setText(ctx.getString( + R.string.introduction_request_for_our_identity_received, + contactName, ir.getName())); + } else { + ui.acceptButton.setVisibility(View.VISIBLE); + ui.acceptButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + intro.respondToIntroduction(ir.getSessionId(), true); + item.setAnswered(true); + notifyItemChanged(position); + } + }); + } ui.declineButton.setVisibility(View.VISIBLE); ui.declineButton.setOnClickListener(new View.OnClickListener() { @Override diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index bf6b9f66cd27eedabd16889b48374bb99b4e338a..eca709bc3af17985b32dab4f5c03ac03d80c9889 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -102,6 +102,12 @@ public interface DatabaseComponent { */ boolean containsGroup(Transaction txn, GroupId g) throws DbException; + /** + * Returns true if the database contains the given local author. + */ + boolean containsLocalAuthor(Transaction txn, AuthorId local) + throws DbException; + /** * Deletes the message with the given ID. The message ID and any other * associated data are not deleted. diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionConstants.java b/briar-api/src/org/briarproject/api/introduction/IntroductionConstants.java index 1ccf2d48053a8f14e2151202982b580493370e71..c3376e36eedf76e38a7551ea5574ce993f117f5a 100644 --- a/briar-api/src/org/briarproject/api/introduction/IntroductionConstants.java +++ b/briar-api/src/org/briarproject/api/introduction/IntroductionConstants.java @@ -57,6 +57,7 @@ public interface IntroductionConstants { String ADDED_CONTACT_ID = "addedContactId"; String NOT_OUR_RESPONSE = "notOurResponse"; String EXISTS = "contactExists"; + String REMOTE_AUTHOR_IS_US = "remoteAuthorIsUs"; String ANSWERED = "answered"; String TASK = "task"; diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java index 227c0500ce5b2f6cc459c87a9104407a068076b0..163eb57be514cd0f372343ec95f97f071ec98afc 100644 --- a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java +++ b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java @@ -6,12 +6,12 @@ import org.briarproject.api.sync.MessageId; public class IntroductionRequest extends IntroductionResponse { private final String message; - private final boolean answered, exists; + private final boolean answered, exists, introducesOtherIdentity; public IntroductionRequest(SessionId sessionId, MessageId messageId, long time, boolean local, boolean sent, boolean seen, boolean read, AuthorId authorId, String name, boolean accepted, String message, - boolean answered, boolean exists) { + boolean answered, boolean exists, boolean introducesOtherIdentity) { super(sessionId, messageId, time, local, sent, seen, read, authorId, name, accepted); @@ -19,6 +19,7 @@ public class IntroductionRequest extends IntroductionResponse { this.message = message; this.answered = answered; this.exists = exists; + this.introducesOtherIdentity = introducesOtherIdentity; } public String getMessage() { @@ -33,4 +34,7 @@ public class IntroductionRequest extends IntroductionResponse { return exists; } + public boolean doesIntroduceOtherIdentity() { + return introducesOtherIdentity; + } } diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index 45ef3b96063731c024375a8745646802eb2a011a..45a9c4cbf41c319125aa2530e8e5b7210031f03b 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -243,6 +243,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { return db.containsGroup(txn, g); } + @Override + public boolean containsLocalAuthor(Transaction transaction, AuthorId local) + throws DbException { + T txn = unbox(transaction); + return db.containsLocalAuthor(txn, local); + } + public void deleteMessage(Transaction transaction, MessageId m) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java b/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java index bc1e3d5f95c9f4b4431d0aa6fedeea318d84c7ba..e713fb8bd8e3ea2a81a46e6ff1d632da5db53e6d 100644 --- a/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java +++ b/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java @@ -47,6 +47,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.OUR_PUBLIC import static org.briarproject.api.introduction.IntroductionConstants.OUR_TIME; import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY; import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; +import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID; import static org.briarproject.api.introduction.IntroductionConstants.STATE; import static org.briarproject.api.introduction.IntroductionConstants.TASK; @@ -328,10 +329,12 @@ public class IntroduceeEngine String name = msg.getString(NAME); String message = msg.getOptionalString(MSG); boolean exists = localState.getBoolean(EXISTS); + boolean introducesOtherIdentity = + localState.getBoolean(REMOTE_AUTHOR_IS_US); IntroductionRequest ir = new IntroductionRequest(sessionId, messageId, time, false, false, false, false, authorId, name, false, - message, false, exists); + message, false, exists, introducesOtherIdentity); return new IntroductionRequestReceivedEvent(contactId, ir); } diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java index b25f299e024870824fbbcd2f8329ae530b1dd085..b329a3abf14c3d1f14347de802d4dd2e91ae2a7b 100644 --- a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java +++ b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java @@ -59,6 +59,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.OUR_PUBLIC import static org.briarproject.api.introduction.IntroductionConstants.OUR_TIME; import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY; import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; +import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; import static org.briarproject.api.introduction.IntroductionConstants.ROLE; import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; import static org.briarproject.api.introduction.IntroductionConstants.STATE; @@ -147,6 +148,17 @@ class IntroduceeManager { d.put(EXISTS, exists); d.put(REMOTE_AUTHOR_ID, remoteAuthorId); + // check if someone is trying to introduce us to ourselves + if(remoteAuthorId.equals(introducer.getLocalAuthorId())) { + LOG.warning("Received Introduction Request to Ourselves"); + throw new FormatException(); + } + + // check if remote author is actually one of our other identities + boolean introducesOtherIdentity = + db.containsLocalAuthor(txn, remoteAuthorId); + d.put(REMOTE_AUTHOR_IS_US, introducesOtherIdentity); + // save local state to database clientHelper.addLocalMessage(txn, localMsg, IntroductionManagerImpl.CLIENT_ID, d, false); diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java index 3550d0148960c92e4677dea85e9180fa6aca70c5..24c89324e1ee33ee1beb398b4e4c01814f3df7be 100644 --- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java @@ -60,6 +60,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.NAME; import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE; import static org.briarproject.api.introduction.IntroductionConstants.READ; import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; +import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1; import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_2; import static org.briarproject.api.introduction.IntroductionConstants.ROLE; @@ -186,9 +187,11 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook state = introduceeManager.initialize(txn, groupId, message); } catch (FormatException e) { if (LOG.isLoggable(WARNING)) { - LOG.warning("Could not initialize introducee state"); + LOG.warning( + "Could not initialize introducee state, deleting..."); LOG.log(WARNING, e.toString(), e); } + deleteMessage(txn, m.getId()); return; } try { @@ -361,7 +364,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook list.add(ir); } else if (type == TYPE_REQUEST) { String message; - boolean answered, exists; + boolean answered, exists, introducesOtherIdentity; if (state.getLong(ROLE) == ROLE_INTRODUCER) { local = true; authorId = @@ -370,6 +373,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook message = msg.getOptionalString(MSG); answered = false; exists = false; + introducesOtherIdentity = false; } else { local = false; authorId = new AuthorId( @@ -378,11 +382,14 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook message = state.getOptionalString(MSG); answered = state.getBoolean(ANSWERED); exists = state.getBoolean(EXISTS); + introducesOtherIdentity = + state.getBoolean(REMOTE_AUTHOR_IS_US); } IntroductionRequest ir = new IntroductionRequest( sessionId, messageId, time, local, s.isSent(), s.isSeen(), read, authorId, name, accepted, - message, answered, exists); + message, answered, exists, + introducesOtherIdentity); list.add(ir); } } catch (FormatException e) { diff --git a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java index 455c93603259bc875a5f05f53d5ba85405df72fd..a4d986d2570d719e60ace1346d15c8068706edcb 100644 --- a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java +++ b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java @@ -51,6 +51,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.NAME; import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE; import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY; import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID; +import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US; import static org.briarproject.api.introduction.IntroductionConstants.ROLE; import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID; @@ -239,6 +240,7 @@ public class IntroduceeManagerTest extends BriarTestCase { state.put(ANSWERED, false); state.put(EXISTS, true); state.put(REMOTE_AUTHOR_ID, introducee2.getAuthor().getId()); + state.put(REMOTE_AUTHOR_IS_US, false); context.checking(new Expectations() {{ oneOf(clock).currentTimeMillis(); @@ -268,6 +270,10 @@ public class IntroduceeManagerTest extends BriarTestCase { introducer.getLocalAuthorId()); will(returnValue(contactExists)); + // checks if remote author is one of our identities + oneOf(db).containsLocalAuthor(txn, introducee2.getAuthor().getId()); + will(returnValue(false)); + // store session state oneOf(clientHelper) .addLocalMessage(txn, localStateMessage, clientId, state,