From 6e3adc087449e3e4b12035a6c5540aa040339418 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Mon, 29 Oct 2018 19:23:22 -0300
Subject: [PATCH] Show alias for introduction notices in private conversation

---
 .../bramble/api/identity/AuthorInfo.java      |  6 ++-
 .../android/contact/ConversationVisitor.java  | 22 ++++----
 .../api/introduction/IntroductionRequest.java | 14 +++--
 .../introduction/IntroductionResponse.java    | 10 +++-
 .../introduction/AbstractProtocolEngine.java  |  5 +-
 .../IntroduceeProtocolEngine.java             |  7 +--
 .../introduction/IntroductionManagerImpl.java | 53 +++++++++++--------
 .../messaging/MessagingControllerImplTest.kt  |  7 ++-
 8 files changed, 81 insertions(+), 43 deletions(-)

diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorInfo.java b/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorInfo.java
index 8c90d9aff0..26f4f33988 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorInfo.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/identity/AuthorInfo.java
@@ -10,7 +10,11 @@ import javax.annotation.concurrent.Immutable;
 public class AuthorInfo {
 
 	public enum Status {
-		NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
+		NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
+
+		public boolean isContact() {
+			return this == UNVERIFIED || this == VERIFIED;
+		}
 	}
 
 	private final Status status;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationVisitor.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationVisitor.java
index 3c33b27c0c..717fee971e 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationVisitor.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationVisitor.java
@@ -24,6 +24,7 @@ import static org.briarproject.briar.android.contact.ConversationRequestItem.Req
 import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
 import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
 import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
+import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
 
 @UiThread
 @NotNullByDefault
@@ -188,33 +189,36 @@ class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
 
 	@Override
 	public ConversationItem visitIntroductionRequest(IntroductionRequest r) {
+		String name = getContactDisplayName(r.getNameable(), r.getAlias());
 		if (r.isLocal()) {
 			String text = ctx.getString(R.string.introduction_request_sent,
-					contactName.getValue(), r.getName());
+					contactName.getValue(), name);
 			return new ConversationNoticeOutItem(text, r);
 		} else {
 			String text = ctx.getString(R.string.introduction_request_received,
-					contactName.getValue(), r.getName());
+					contactName.getValue(), name);
 			return new ConversationRequestItem(text, INTRODUCTION, r);
 		}
 	}
 
 	@Override
 	public ConversationItem visitIntroductionResponse(IntroductionResponse r) {
+		String introducedAuthor =
+				getContactDisplayName(r.getIntroducedAuthor(),
+						r.getIntroducedAuthorInfo().getAlias());
 		if (r.isLocal()) {
 			String text;
 			if (r.wasAccepted()) {
-				String introducee = r.getIntroducedAuthor().getName();
 				text = ctx.getString(
 						R.string.introduction_response_accepted_sent,
-						introducee)
+						introducedAuthor)
 						+ "\n\n" + ctx.getString(
 						R.string.introduction_response_accepted_sent_info,
-						introducee);
+						introducedAuthor);
 			} else {
 				text = ctx.getString(
 						R.string.introduction_response_declined_sent,
-						r.getIntroducedAuthor().getName());
+						introducedAuthor);
 			}
 			return new ConversationNoticeOutItem(text, r);
 		} else {
@@ -223,17 +227,17 @@ class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
 				text = ctx.getString(
 						R.string.introduction_response_accepted_received,
 						contactName.getValue(),
-						r.getIntroducedAuthor().getName());
+						introducedAuthor);
 			} else if (r.isIntroducer()) {
 				text = ctx.getString(
 						R.string.introduction_response_declined_received,
 						contactName.getValue(),
-						r.getIntroducedAuthor().getName());
+						introducedAuthor);
 			} else {
 				text = ctx.getString(
 						R.string.introduction_response_declined_received_by_introducee,
 						contactName.getValue(),
-						r.getIntroducedAuthor().getName());
+						introducedAuthor);
 			}
 			return new ConversationNoticeInItem(text, r);
 		}
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java
index 5cbe9e0dd9..1bc2cd5cbe 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionRequest.java
@@ -1,6 +1,7 @@
 package org.briarproject.briar.api.introduction;
 
 import org.briarproject.bramble.api.identity.Author;
+import org.briarproject.bramble.api.identity.AuthorInfo;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
@@ -15,19 +16,24 @@ import javax.annotation.concurrent.Immutable;
 @NotNullByDefault
 public class IntroductionRequest extends PrivateRequest<Author> {
 
-	private final boolean contact;
+	private final AuthorInfo authorInfo;
 
 	public IntroductionRequest(MessageId messageId, GroupId groupId,
 			long time, boolean local, boolean sent, boolean seen, boolean read,
 			SessionId sessionId, Author author, @Nullable String text,
-			boolean answered, boolean contact) {
+			boolean answered, AuthorInfo authorInfo) {
 		super(messageId, groupId, time, local, sent, seen, read, sessionId,
 				author, text, answered);
-		this.contact = contact;
+		this.authorInfo = authorInfo;
+	}
+
+	@Nullable
+	public String getAlias() {
+		return authorInfo.getAlias();
 	}
 
 	public boolean isContact() {
-		return contact;
+		return authorInfo.getStatus().isContact();
 	}
 
 	@Override
diff --git a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java
index b03f8d7ca9..960c55e4d6 100644
--- a/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java
+++ b/briar-api/src/main/java/org/briarproject/briar/api/introduction/IntroductionResponse.java
@@ -1,6 +1,7 @@
 package org.briarproject.briar.api.introduction;
 
 import org.briarproject.bramble.api.identity.Author;
+import org.briarproject.bramble.api.identity.AuthorInfo;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.sync.GroupId;
 import org.briarproject.bramble.api.sync.MessageId;
@@ -17,14 +18,17 @@ import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
 public class IntroductionResponse extends PrivateResponse {
 
 	private final Author introducedAuthor;
+	private final AuthorInfo introducedAuthorInfo;
 	private final Role ourRole;
 
 	public IntroductionResponse(MessageId messageId, GroupId groupId, long time,
 			boolean local, boolean sent, boolean seen, boolean read,
-			SessionId sessionId, boolean accepted, Author author, Role role) {
+			SessionId sessionId, boolean accepted, Author author,
+			AuthorInfo introducedAuthorInfo, Role role) {
 		super(messageId, groupId, time, local, sent, seen, read, sessionId,
 				accepted);
 		this.introducedAuthor = author;
+		this.introducedAuthorInfo = introducedAuthorInfo;
 		this.ourRole = role;
 	}
 
@@ -32,6 +36,10 @@ public class IntroductionResponse extends PrivateResponse {
 		return introducedAuthor;
 	}
 
+	public AuthorInfo getIntroducedAuthorInfo() {
+		return introducedAuthorInfo;
+	}
+
 	public boolean isIntroducer() {
 		return ourRole == INTRODUCER;
 	}
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java
index 8438974e67..53ad748611 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/AbstractProtocolEngine.java
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
 import org.briarproject.bramble.api.identity.AuthorId;
+import org.briarproject.bramble.api.identity.AuthorInfo;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 import org.briarproject.bramble.api.plugin.TransportId;
@@ -149,11 +150,13 @@ abstract class AbstractProtocolEngine<S extends Session>
 			throws DbException {
 		AuthorId localAuthorId = identityManager.getLocalAuthor(txn).getId();
 		Contact c = contactManager.getContact(txn, sender, localAuthorId);
+		AuthorInfo otherAuthorInfo =
+				contactManager.getAuthorInfo(txn, otherAuthor.getId());
 		IntroductionResponse response =
 				new IntroductionResponse(m.getMessageId(), m.getGroupId(),
 						m.getTimestamp(), false, false, false, false,
 						s.getSessionId(), m instanceof AcceptMessage,
-						otherAuthor, s.getRole());
+						otherAuthor, otherAuthorInfo, s.getRole());
 		IntroductionResponseReceivedEvent e =
 				new IntroductionResponseReceivedEvent(response, c.getId());
 		txn.attach(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java
index b63da62078..ae055bb9b7 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java
@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.db.ContactExistsException;
 import org.briarproject.bramble.api.db.DatabaseComponent;
 import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.Transaction;
+import org.briarproject.bramble.api.identity.AuthorInfo;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.identity.LocalAuthor;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -251,12 +252,12 @@ class IntroduceeProtocolEngine
 		LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
 		Contact c = contactManager.getContact(txn, s.getIntroducer().getId(),
 				localAuthor.getId());
-		boolean contactExists = contactManager
-				.contactExists(txn, m.getAuthor().getId(), localAuthor.getId());
+		AuthorInfo authorInfo =
+				contactManager.getAuthorInfo(txn, m.getAuthor().getId());
 		IntroductionRequest request = new IntroductionRequest(m.getMessageId(),
 				m.getGroupId(), m.getTimestamp(), false, false, false, false,
 				s.getSessionId(), m.getAuthor(), m.getText(), false,
-				contactExists);
+				authorInfo);
 		IntroductionRequestReceivedEvent e =
 				new IntroductionRequestReceivedEvent(request, c.getId());
 		txn.attach(e);
diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java
index 6d6727aec7..defc19c534 100644
--- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java
@@ -15,6 +15,8 @@ import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.Metadata;
 import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
+import org.briarproject.bramble.api.identity.AuthorId;
+import org.briarproject.bramble.api.identity.AuthorInfo;
 import org.briarproject.bramble.api.identity.IdentityManager;
 import org.briarproject.bramble.api.identity.LocalAuthor;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -39,6 +41,7 @@ import org.briarproject.briar.introduction.IntroducerSession.Introducee;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -408,6 +411,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
 					.getMessageMetadataAsDictionary(txn, contactGroupId, query);
 			List<PrivateMessageHeader> messages =
 					new ArrayList<>(results.size());
+			Map<AuthorId, AuthorInfo> authorInfos = new HashMap<>();
 			for (Entry<MessageId, BdfDictionary> e : results.entrySet()) {
 				MessageId m = e.getKey();
 				MessageMetadata meta =
@@ -419,15 +423,17 @@ class IntroductionManagerImpl extends ConversationClientImpl
 				if (type == REQUEST) {
 					messages.add(
 							parseInvitationRequest(txn, contactGroupId, m,
-									meta, status, ss.bdfSession));
+									meta, status, ss.bdfSession, authorInfos));
 				} else if (type == ACCEPT) {
 					messages.add(
-							parseInvitationResponse(contactGroupId, m, meta,
-									status, ss.bdfSession, true));
+							parseInvitationResponse(txn, contactGroupId, m,
+									meta, status, ss.bdfSession, authorInfos,
+									true));
 				} else if (type == DECLINE) {
 					messages.add(
-							parseInvitationResponse(contactGroupId, m, meta,
-									status, ss.bdfSession, false));
+							parseInvitationResponse(txn, contactGroupId, m,
+									meta, status, ss.bdfSession, authorInfos,
+									false));
 				}
 			}
 			return messages;
@@ -438,43 +444,41 @@ class IntroductionManagerImpl extends ConversationClientImpl
 
 	private IntroductionRequest parseInvitationRequest(Transaction txn,
 			GroupId contactGroupId, MessageId m, MessageMetadata meta,
-			MessageStatus status, BdfDictionary bdfSession)
+			MessageStatus status, BdfDictionary bdfSession,
+			Map<AuthorId, AuthorInfo> authorInfos)
 			throws DbException, FormatException {
 		Role role = sessionParser.getRole(bdfSession);
 		SessionId sessionId;
-		Author author;
 		if (role == INTRODUCER) {
 			IntroducerSession session =
 					sessionParser.parseIntroducerSession(bdfSession);
 			sessionId = session.getSessionId();
-			if (contactGroupId.equals(session.getIntroduceeA().groupId)) {
-				author = session.getIntroduceeB().author;
-			} else {
-				author = session.getIntroduceeA().author;
-			}
 		} else if (role == INTRODUCEE) {
 			IntroduceeSession session = sessionParser
 					.parseIntroduceeSession(contactGroupId, bdfSession);
 			sessionId = session.getSessionId();
-			author = session.getRemote().author;
 		} else throw new AssertionError();
 		Message msg = clientHelper.getMessage(txn, m);
 		BdfList body = clientHelper.toList(msg);
 		RequestMessage rm = messageParser.parseRequestMessage(msg, body);
 		String text = rm.getText();
-		LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
-		boolean contactExists = contactManager
-				.contactExists(txn, rm.getAuthor().getId(),
-						localAuthor.getId());
+		Author author = rm.getAuthor();
+		AuthorInfo authorInfo = authorInfos.get(author.getId());
+		if (authorInfo == null) {
+			authorInfo = contactManager.getAuthorInfo(txn, author.getId());
+			authorInfos.put(author.getId(), authorInfo);
+		}
 		return new IntroductionRequest(m, contactGroupId, meta.getTimestamp(),
 				meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(),
 				sessionId, author, text, !meta.isAvailableToAnswer(),
-				contactExists);
+				authorInfo);
 	}
 
-	private IntroductionResponse parseInvitationResponse(GroupId contactGroupId,
-			MessageId m, MessageMetadata meta, MessageStatus status,
-			BdfDictionary bdfSession, boolean accept) throws FormatException {
+	private IntroductionResponse parseInvitationResponse(Transaction txn,
+			GroupId contactGroupId, MessageId m, MessageMetadata meta,
+			MessageStatus status, BdfDictionary bdfSession,
+			Map<AuthorId, AuthorInfo> authorInfos, boolean accept)
+			throws FormatException, DbException {
 		Role role = sessionParser.getRole(bdfSession);
 		SessionId sessionId;
 		Author author;
@@ -493,9 +497,14 @@ class IntroductionManagerImpl extends ConversationClientImpl
 			sessionId = session.getSessionId();
 			author = session.getRemote().author;
 		} else throw new AssertionError();
+		AuthorInfo authorInfo = authorInfos.get(author.getId());
+		if (authorInfo == null) {
+			authorInfo = contactManager.getAuthorInfo(txn, author.getId());
+			authorInfos.put(author.getId(), authorInfo);
+		}
 		return new IntroductionResponse(m, contactGroupId, meta.getTimestamp(),
 				meta.isLocal(), status.isSent(), status.isSeen(), meta.isRead(),
-				sessionId, accept, author, role);
+				sessionId, accept, author, authorInfo, role);
 	}
 
 	private void removeSessionWithIntroducer(Transaction txn,
diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt
index f5728603d9..88e4715980 100644
--- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt
+++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt
@@ -7,6 +7,9 @@ import io.javalin.json.JavalinJson.toJson
 import io.mockk.*
 import org.briarproject.bramble.api.contact.ContactId
 import org.briarproject.bramble.api.db.NoSuchContactException
+import org.briarproject.bramble.api.identity.AuthorInfo
+import org.briarproject.bramble.api.identity.AuthorInfo.Status.UNVERIFIED
+import org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED
 import org.briarproject.bramble.test.ImmediateExecutor
 import org.briarproject.bramble.test.TestUtils.getRandomId
 import org.briarproject.bramble.util.StringUtils.getRandomString
@@ -61,7 +64,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
     fun listIntroductionRequest() {
         val request = IntroductionRequest(
             message.id, group.id, timestamp, true, true, false, true, sessionId, author, text,
-            false, false
+            false, AuthorInfo(UNVERIFIED)
         )
 
         expectGetContact()
@@ -200,7 +203,7 @@ internal class MessagingControllerImplTest : ControllerTest() {
     fun testIntroductionRequestWithNullText() {
         val request = IntroductionRequest(
             message.id, group.id, timestamp, true, true, false, true, sessionId, author, null,
-            false, false
+            false, AuthorInfo(VERIFIED)
         )
         val json = """
             {
-- 
GitLab