diff --git a/briar-android/res/layout/list_item_introduction_in.xml b/briar-android/res/layout/list_item_introduction_in.xml
index 5daea0608..2f157fad6 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 bfd82ba9f..ca1e962f4 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -155,6 +155,7 @@
You have asked to introduce %1$s to %2$s.
%1$s has asked to introduce you to %2$s. Do you want to add %2$s to your contact list?
%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:
+ %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:
%1$s has asked to introduce you to %2$s.
You accepted the introduction to %1$s.
You declined the introduction to %1$s.
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
index 4e8267663..3a90e4f99 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 bf6b9f66c..eca709bc3 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 1ccf2d480..c3376e36e 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 227c0500c..163eb57be 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 45ef3b960..45a9c4cbf 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 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 bc1e3d5f9..e713fb8bd 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 b25f299e0..b329a3abf 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 3550d0148..24c89324e 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 455c93603..a4d986d25 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,