From 4b7a32a5eef404837e86502339183c154a256dfd Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Mon, 4 Apr 2016 12:04:17 -0300
Subject: [PATCH] Find correct session state in case the same one is used
 twice.

The code made the assumption that a session state can be identified by
the unique session ID. However, when multiple identities from the same
device are involved, there are two sessions with the same ID running on
the device.

Hence, a second identifying criteria has to be used to uniquely identify
the correct session. Here, the ID of the group was chosen.
Unfortunately, the session state can not be cached easily anymore
leading to a small performance penalty when getting all messages for the
UI.
---
 .../android/contact/ConversationActivity.java |  4 +-
 .../api/introduction/IntroductionManager.java | 13 ++---
 .../introduction/IntroduceeManager.java       | 21 ++++++---
 .../introduction/IntroductionManagerImpl.java | 47 +++++++++++--------
 4 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 747c08caaf..d10a3d31cc 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -663,9 +663,9 @@ public class ConversationActivity extends BriarActivity
 			public void run() {
 				try {
 					if (accept) {
-						introductionManager.acceptIntroduction(sessionId);
+						introductionManager.acceptIntroduction(contactId, sessionId);
 					} else {
-						introductionManager.declineIntroduction(sessionId);
+						introductionManager.declineIntroduction(contactId, sessionId);
 					}
 					loadMessages();
 				} catch (DbException e) {
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java b/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
index 882ccbf112..f83581ed7b 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionManager.java
@@ -8,6 +8,7 @@ import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Transaction;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.Group;
+import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 
 import java.util.Collection;
@@ -26,14 +27,14 @@ public interface IntroductionManager {
 	/**
 	 * Accept an introduction that had been made
 	 */
-	void acceptIntroduction(final SessionId sessionId)
-			throws DbException, FormatException;
+	void acceptIntroduction(final ContactId contactId,
+			final SessionId sessionId) throws DbException, FormatException;
 
 	/**
 	 * Decline an introduction that had been made
 	 */
-	void declineIntroduction(final SessionId sessionId)
-			throws DbException, FormatException;
+	void declineIntroduction(final ContactId contactId,
+			final SessionId sessionId) throws DbException, FormatException;
 
 	/**
 	 * Get all introduction messages for the contact with this contactId
@@ -46,8 +47,8 @@ public interface IntroductionManager {
 
 
 	/** Get the session state for the given session ID */
-	BdfDictionary getSessionState(Transaction txn, byte[] sessionId)
-			throws DbException, FormatException;
+	BdfDictionary getSessionState(Transaction txn, GroupId groupId,
+			byte[] sessionId) throws DbException, FormatException;
 
 	/** Gets the group used for introductions with Contact c */
 	Group getIntroductionGroup(Contact c);
diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java
index be16ff1e49..174d2af21a 100644
--- a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java
+++ b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java
@@ -28,6 +28,7 @@ import org.briarproject.api.introduction.IntroductionManager;
 import org.briarproject.api.introduction.SessionId;
 import org.briarproject.api.properties.TransportProperties;
 import org.briarproject.api.properties.TransportPropertyManager;
+import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
@@ -157,11 +158,14 @@ class IntroduceeManager {
 		processStateUpdate(txn, engine.onMessageReceived(state, message));
 	}
 
-	public void acceptIntroduction(Transaction txn,
+	public void acceptIntroduction(Transaction txn, final ContactId contactId,
 			final SessionId sessionId) throws DbException, FormatException {
 
-		BdfDictionary state =
-				introductionManager.getSessionState(txn, sessionId.getBytes());
+		Contact c = contactManager.getContact(contactId);
+		Group g = introductionManager.getIntroductionGroup(c);
+
+		BdfDictionary state = introductionManager
+				.getSessionState(txn, g.getId(), sessionId.getBytes());
 
 		// get data to connect and derive a shared secret later
 		long now = clock.currentTimeMillis();
@@ -188,11 +192,14 @@ class IntroduceeManager {
 		processStateUpdate(txn, engine.onLocalAction(state, localAction));
 	}
 
-	public void declineIntroduction(Transaction txn, final SessionId sessionId)
-			throws DbException, FormatException {
+	public void declineIntroduction(Transaction txn, final ContactId contactId,
+			final SessionId sessionId) throws DbException, FormatException {
+
+		Contact c = contactManager.getContact(contactId);
+		Group g = introductionManager.getIntroductionGroup(c);
 
-		BdfDictionary state =
-				introductionManager.getSessionState(txn, sessionId.getBytes());
+		BdfDictionary state = introductionManager
+				.getSessionState(txn, g.getId(), sessionId.getBytes());
 
 		// update session state
 		state.put(ACCEPT, false);
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
index e28af29e4d..30cfe7083f 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
@@ -62,6 +62,8 @@ import static org.briarproject.api.introduction.IntroductionConstants.CONTACT_ID
 import static org.briarproject.api.introduction.IntroductionConstants.CONTACT_ID_2;
 import static org.briarproject.api.introduction.IntroductionConstants.EXISTS;
 import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
+import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_1;
+import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_2;
 import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
 import static org.briarproject.api.introduction.IntroductionConstants.MSG;
 import static org.briarproject.api.introduction.IntroductionConstants.NAME;
@@ -227,7 +229,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
 		else if (type == TYPE_RESPONSE || type == TYPE_ACK || type == TYPE_ABORT) {
 			BdfDictionary state;
 			try {
-				state = getSessionState(txn,
+				state = getSessionState(txn, groupId,
 						message.getRaw(SESSION_ID, new byte[0]));
 			} catch (FormatException e) {
 				LOG.warning("Could not find state for message, deleting...");
@@ -279,12 +281,12 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
 	}
 
 	@Override
-	public void acceptIntroduction(final SessionId sessionId)
-			throws DbException, FormatException {
+	public void acceptIntroduction(final ContactId contactId,
+			final SessionId sessionId) throws DbException, FormatException {
 
 		Transaction txn = db.startTransaction(false);
 		try {
-			introduceeManager.acceptIntroduction(txn, sessionId);
+			introduceeManager.acceptIntroduction(txn, contactId, sessionId);
 			txn.setComplete();
 		} finally {
 			db.endTransaction(txn);
@@ -292,12 +294,12 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
 	}
 
 	@Override
-	public void declineIntroduction(final SessionId sessionId)
-			throws DbException, FormatException {
+	public void declineIntroduction(final ContactId contactId,
+			final SessionId sessionId) throws DbException, FormatException {
 
 		Transaction txn = db.startTransaction(false);
 		try {
-			introduceeManager.declineIntroduction(txn, sessionId);
+			introduceeManager.declineIntroduction(txn, contactId, sessionId);
 			txn.setComplete();
 		} finally {
 			db.endTransaction(txn);
@@ -322,8 +324,6 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
 			statuses = db.getMessageStatus(txn, contactId, g);
 
 			// turn messages into classes for the UI
-			Map<SessionId, BdfDictionary> sessionStates =
-					new HashMap<SessionId, BdfDictionary>();
 			for (MessageStatus s : statuses) {
 				MessageId messageId = s.getMessageId();
 				BdfDictionary msg = metadata.get(messageId);
@@ -335,11 +335,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
 
 					// get session state
 					SessionId sessionId = new SessionId(msg.getRaw(SESSION_ID));
-					BdfDictionary state = sessionStates.get(sessionId);
-					if (state == null) {
-						state = getSessionState(txn, sessionId.getBytes());
-					}
-					sessionStates.put(sessionId, state);
+					BdfDictionary state =
+							getSessionState(txn, g, sessionId.getBytes());
 
 					boolean local;
 					long time = msg.getLong(MESSAGE_TIME);
@@ -453,19 +450,31 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
 		}
 	}
 
-	public BdfDictionary getSessionState(Transaction txn, byte[] sessionId)
-			throws DbException, FormatException {
+	public BdfDictionary getSessionState(Transaction txn, GroupId groupId,
+			byte[] sessionId) throws DbException, FormatException {
 
 		try {
-			return clientHelper.getMessageMetadataAsDictionary(txn,
-					new MessageId(sessionId));
+			// See if we can find the state directly for the introducer
+			BdfDictionary state = clientHelper
+					.getMessageMetadataAsDictionary(txn,
+							new MessageId(sessionId));
+			GroupId g1 = new GroupId(state.getRaw(GROUP_ID_1));
+			GroupId g2 = new GroupId(state.getRaw(GROUP_ID_2));
+			if (!g1.equals(groupId) && !g2.equals(groupId)) {
+				throw new NoSuchMessageException();
+			}
+			return state;
 		} catch (NoSuchMessageException e) {
+			// State not found directly, so iterate over all states
+			// to find state for introducee
 			Map<MessageId, BdfDictionary> map = clientHelper
 					.getMessageMetadataAsDictionary(txn,
 							localGroup.getId());
 			for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
 				if (Arrays.equals(m.getValue().getRaw(SESSION_ID), sessionId)) {
-					return m.getValue();
+					BdfDictionary state = m.getValue();
+					GroupId g = new GroupId(state.getRaw(GROUP_ID));
+					if (g.equals(groupId)) return state;
 				}
 			}
 			if (LOG.isLoggable(WARNING)) {
-- 
GitLab