mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 04:18:53 +01:00
This addresses two types of introduction corner cases:
* force decline when two of our own identities are introduced to each other * throw away introduction requests to the same identity (impossible to trigger from UI) Closes #284
This commit is contained in:
@@ -36,7 +36,7 @@
|
|||||||
android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
|
android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
|
||||||
android:layout_alignEnd="@+id/introductionText"
|
android:layout_alignEnd="@+id/introductionText"
|
||||||
android:layout_alignRight="@+id/introductionText"
|
android:layout_alignRight="@+id/introductionText"
|
||||||
android:layout_below="@+id/acceptButton"
|
android:layout_below="@+id/declineButton"
|
||||||
android:textColor="@color/private_message_date"
|
android:textColor="@color/private_message_date"
|
||||||
android:textSize="@dimen/text_size_tiny"
|
android:textSize="@dimen/text_size_tiny"
|
||||||
tools:text="Dec 24, 13:37"/>
|
tools:text="Dec 24, 13:37"/>
|
||||||
@@ -46,7 +46,6 @@
|
|||||||
style="@style/BriarButtonFlat.Positive"
|
style="@style/BriarButtonFlat.Positive"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="-15dp"
|
|
||||||
android:layout_alignEnd="@+id/introductionText"
|
android:layout_alignEnd="@+id/introductionText"
|
||||||
android:layout_alignRight="@+id/introductionText"
|
android:layout_alignRight="@+id/introductionText"
|
||||||
android:layout_below="@+id/introductionText"
|
android:layout_below="@+id/introductionText"
|
||||||
@@ -57,6 +56,7 @@
|
|||||||
style="@style/BriarButtonFlat.Negative"
|
style="@style/BriarButtonFlat.Negative"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="-15dp"
|
||||||
android:layout_below="@+id/introductionText"
|
android:layout_below="@+id/introductionText"
|
||||||
android:layout_toLeftOf="@+id/acceptButton"
|
android:layout_toLeftOf="@+id/acceptButton"
|
||||||
android:layout_toStartOf="@+id/acceptButton"
|
android:layout_toStartOf="@+id/acceptButton"
|
||||||
|
|||||||
@@ -155,6 +155,7 @@
|
|||||||
<string name="introduction_request_sent">You have asked to introduce %1$s to %2$s.</string>
|
<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_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_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_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_accepted_sent">You accepted the introduction to %1$s.</string>
|
||||||
<string name="introduction_response_declined_sent">You declined the introduction to %1$s.</string>
|
<string name="introduction_response_declined_sent">You declined the introduction to %1$s.</string>
|
||||||
|
|||||||
@@ -261,15 +261,23 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
contactName, ir.getName()));
|
contactName, ir.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.acceptButton.setVisibility(View.VISIBLE);
|
if (item.getIntroductionRequest().doesIntroduceOtherIdentity()) {
|
||||||
ui.acceptButton.setOnClickListener(new View.OnClickListener() {
|
// don't allow accept when one of our identities is introduced
|
||||||
@Override
|
ui.acceptButton.setVisibility(View.GONE);
|
||||||
public void onClick(View v) {
|
ui.text.setText(ctx.getString(
|
||||||
intro.respondToIntroduction(ir.getSessionId(), true);
|
R.string.introduction_request_for_our_identity_received,
|
||||||
item.setAnswered(true);
|
contactName, ir.getName()));
|
||||||
notifyItemChanged(position);
|
} 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.setVisibility(View.VISIBLE);
|
||||||
ui.declineButton.setOnClickListener(new View.OnClickListener() {
|
ui.declineButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
boolean containsGroup(Transaction txn, GroupId g) throws DbException;
|
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
|
* Deletes the message with the given ID. The message ID and any other
|
||||||
* associated data are not deleted.
|
* associated data are not deleted.
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public interface IntroductionConstants {
|
|||||||
String ADDED_CONTACT_ID = "addedContactId";
|
String ADDED_CONTACT_ID = "addedContactId";
|
||||||
String NOT_OUR_RESPONSE = "notOurResponse";
|
String NOT_OUR_RESPONSE = "notOurResponse";
|
||||||
String EXISTS = "contactExists";
|
String EXISTS = "contactExists";
|
||||||
|
String REMOTE_AUTHOR_IS_US = "remoteAuthorIsUs";
|
||||||
String ANSWERED = "answered";
|
String ANSWERED = "answered";
|
||||||
|
|
||||||
String TASK = "task";
|
String TASK = "task";
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import org.briarproject.api.sync.MessageId;
|
|||||||
public class IntroductionRequest extends IntroductionResponse {
|
public class IntroductionRequest extends IntroductionResponse {
|
||||||
|
|
||||||
private final String message;
|
private final String message;
|
||||||
private final boolean answered, exists;
|
private final boolean answered, exists, introducesOtherIdentity;
|
||||||
|
|
||||||
public IntroductionRequest(SessionId sessionId, MessageId messageId,
|
public IntroductionRequest(SessionId sessionId, MessageId messageId,
|
||||||
long time, boolean local, boolean sent, boolean seen, boolean read,
|
long time, boolean local, boolean sent, boolean seen, boolean read,
|
||||||
AuthorId authorId, String name, boolean accepted, String message,
|
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,
|
super(sessionId, messageId, time, local, sent, seen, read, authorId,
|
||||||
name, accepted);
|
name, accepted);
|
||||||
@@ -19,6 +19,7 @@ public class IntroductionRequest extends IntroductionResponse {
|
|||||||
this.message = message;
|
this.message = message;
|
||||||
this.answered = answered;
|
this.answered = answered;
|
||||||
this.exists = exists;
|
this.exists = exists;
|
||||||
|
this.introducesOtherIdentity = introducesOtherIdentity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
@@ -33,4 +34,7 @@ public class IntroductionRequest extends IntroductionResponse {
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean doesIntroduceOtherIdentity() {
|
||||||
|
return introducesOtherIdentity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,6 +243,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.containsGroup(txn, g);
|
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)
|
public void deleteMessage(Transaction transaction, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
|
|||||||
@@ -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.OUR_TIME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
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_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.SESSION_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
|
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.TASK;
|
import static org.briarproject.api.introduction.IntroductionConstants.TASK;
|
||||||
@@ -328,10 +329,12 @@ public class IntroduceeEngine
|
|||||||
String name = msg.getString(NAME);
|
String name = msg.getString(NAME);
|
||||||
String message = msg.getOptionalString(MSG);
|
String message = msg.getOptionalString(MSG);
|
||||||
boolean exists = localState.getBoolean(EXISTS);
|
boolean exists = localState.getBoolean(EXISTS);
|
||||||
|
boolean introducesOtherIdentity =
|
||||||
|
localState.getBoolean(REMOTE_AUTHOR_IS_US);
|
||||||
|
|
||||||
IntroductionRequest ir = new IntroductionRequest(sessionId, messageId,
|
IntroductionRequest ir = new IntroductionRequest(sessionId, messageId,
|
||||||
time, false, false, false, false, authorId, name, false,
|
time, false, false, false, false, authorId, name, false,
|
||||||
message, false, exists);
|
message, false, exists, introducesOtherIdentity);
|
||||||
return new IntroductionRequestReceivedEvent(contactId, ir);
|
return new IntroductionRequestReceivedEvent(contactId, ir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.OUR_TIME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
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_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;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
|
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
|
import static org.briarproject.api.introduction.IntroductionConstants.STATE;
|
||||||
@@ -147,6 +148,17 @@ class IntroduceeManager {
|
|||||||
d.put(EXISTS, exists);
|
d.put(EXISTS, exists);
|
||||||
d.put(REMOTE_AUTHOR_ID, remoteAuthorId);
|
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
|
// save local state to database
|
||||||
clientHelper.addLocalMessage(txn, localMsg,
|
clientHelper.addLocalMessage(txn, localMsg,
|
||||||
IntroductionManagerImpl.CLIENT_ID, d, false);
|
IntroductionManagerImpl.CLIENT_ID, d, false);
|
||||||
|
|||||||
@@ -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.NOT_OUR_RESPONSE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.READ;
|
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_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_1;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_2;
|
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_2;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ROLE;
|
import static org.briarproject.api.introduction.IntroductionConstants.ROLE;
|
||||||
@@ -186,9 +187,11 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
state = introduceeManager.initialize(txn, groupId, message);
|
state = introduceeManager.initialize(txn, groupId, message);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) {
|
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);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
|
deleteMessage(txn, m.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -361,7 +364,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
list.add(ir);
|
list.add(ir);
|
||||||
} else if (type == TYPE_REQUEST) {
|
} else if (type == TYPE_REQUEST) {
|
||||||
String message;
|
String message;
|
||||||
boolean answered, exists;
|
boolean answered, exists, introducesOtherIdentity;
|
||||||
if (state.getLong(ROLE) == ROLE_INTRODUCER) {
|
if (state.getLong(ROLE) == ROLE_INTRODUCER) {
|
||||||
local = true;
|
local = true;
|
||||||
authorId =
|
authorId =
|
||||||
@@ -370,6 +373,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
message = msg.getOptionalString(MSG);
|
message = msg.getOptionalString(MSG);
|
||||||
answered = false;
|
answered = false;
|
||||||
exists = false;
|
exists = false;
|
||||||
|
introducesOtherIdentity = false;
|
||||||
} else {
|
} else {
|
||||||
local = false;
|
local = false;
|
||||||
authorId = new AuthorId(
|
authorId = new AuthorId(
|
||||||
@@ -378,11 +382,14 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
message = state.getOptionalString(MSG);
|
message = state.getOptionalString(MSG);
|
||||||
answered = state.getBoolean(ANSWERED);
|
answered = state.getBoolean(ANSWERED);
|
||||||
exists = state.getBoolean(EXISTS);
|
exists = state.getBoolean(EXISTS);
|
||||||
|
introducesOtherIdentity =
|
||||||
|
state.getBoolean(REMOTE_AUTHOR_IS_US);
|
||||||
}
|
}
|
||||||
IntroductionRequest ir = new IntroductionRequest(
|
IntroductionRequest ir = new IntroductionRequest(
|
||||||
sessionId, messageId, time, local, s.isSent(),
|
sessionId, messageId, time, local, s.isSent(),
|
||||||
s.isSeen(), read, authorId, name, accepted,
|
s.isSeen(), read, authorId, name, accepted,
|
||||||
message, answered, exists);
|
message, answered, exists,
|
||||||
|
introducesOtherIdentity);
|
||||||
list.add(ir);
|
list.add(ir);
|
||||||
}
|
}
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
|
|||||||
@@ -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.NOT_OUR_RESPONSE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
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_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;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
|
import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID;
|
||||||
@@ -239,6 +240,7 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
|||||||
state.put(ANSWERED, false);
|
state.put(ANSWERED, false);
|
||||||
state.put(EXISTS, true);
|
state.put(EXISTS, true);
|
||||||
state.put(REMOTE_AUTHOR_ID, introducee2.getAuthor().getId());
|
state.put(REMOTE_AUTHOR_ID, introducee2.getAuthor().getId());
|
||||||
|
state.put(REMOTE_AUTHOR_IS_US, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
@@ -268,6 +270,10 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
|||||||
introducer.getLocalAuthorId());
|
introducer.getLocalAuthorId());
|
||||||
will(returnValue(contactExists));
|
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
|
// store session state
|
||||||
oneOf(clientHelper)
|
oneOf(clientHelper)
|
||||||
.addLocalMessage(txn, localStateMessage, clientId, state,
|
.addLocalMessage(txn, localStateMessage, clientId, state,
|
||||||
|
|||||||
Reference in New Issue
Block a user