From cd24be7e42b9e7864e8ae495017f58e107f1fe5b Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Wed, 17 Apr 2019 18:06:58 +0100
Subject: [PATCH] Add unit tests for pending contact factory.

---
 .../contact/PendingContactFactoryImpl.java    |   2 +-
 .../PendingContactFactoryImplTest.java        | 121 ++++++++++++++++++
 2 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/contact/PendingContactFactoryImplTest.java

diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/PendingContactFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/PendingContactFactoryImpl.java
index 36a627013c..4e4ac27828 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/contact/PendingContactFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/PendingContactFactoryImpl.java
@@ -44,7 +44,7 @@ class PendingContactFactoryImpl implements PendingContactFactory {
 
 	private PublicKey parseHandshakeLink(String link) throws FormatException {
 		Matcher matcher = LINK_REGEX.matcher(link);
-		if (!matcher.matches()) throw new FormatException();
+		if (!matcher.find()) throw new FormatException();
 		link = matcher.group(); // Discard anything before or after the link
 		if (link.startsWith("briar://")) link = link.substring(8);
 		byte[] base32 = Base32.decode(link, false);
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/contact/PendingContactFactoryImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/contact/PendingContactFactoryImplTest.java
new file mode 100644
index 0000000000..bbcde760b3
--- /dev/null
+++ b/bramble-core/src/test/java/org/briarproject/bramble/contact/PendingContactFactoryImplTest.java
@@ -0,0 +1,121 @@
+package org.briarproject.bramble.contact;
+
+import org.briarproject.bramble.api.FormatException;
+import org.briarproject.bramble.api.contact.PendingContact;
+import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.KeyParser;
+import org.briarproject.bramble.api.crypto.PublicKey;
+import org.briarproject.bramble.api.system.Clock;
+import org.briarproject.bramble.test.BrambleMockTestCase;
+import org.briarproject.bramble.util.Base32;
+import org.jmock.Expectations;
+import org.junit.Test;
+
+import java.security.GeneralSecurityException;
+
+import static java.lang.System.arraycopy;
+import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.BASE32_LINK_BYTES;
+import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.FORMAT_VERSION;
+import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.ID_LABEL;
+import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.RAW_LINK_BYTES;
+import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
+import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
+import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
+import static org.briarproject.bramble.test.TestUtils.getRandomId;
+import static org.briarproject.bramble.util.StringUtils.getRandomString;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class PendingContactFactoryImplTest extends BrambleMockTestCase {
+
+	private final CryptoComponent crypto = context.mock(CryptoComponent.class);
+	private final Clock clock = context.mock(Clock.class);
+	private final KeyParser keyParser = context.mock(KeyParser.class);
+	private final PublicKey publicKey = context.mock(PublicKey.class);
+
+	private final PendingContactFactory pendingContactFactory =
+			new PendingContactFactoryImpl(crypto, clock);
+	private final String alias = getRandomString(MAX_AUTHOR_NAME_LENGTH);
+	private final byte[] publicKeyBytes = getRandomBytes(RAW_LINK_BYTES - 1);
+	private final byte[] idBytes = getRandomId();
+	private final long timestamp = System.currentTimeMillis();
+
+	@Test(expected = FormatException.class)
+	public void testRejectsSyntacticallyInvalidLink() throws Exception {
+		pendingContactFactory.createPendingContact("briar://potato", alias);
+	}
+
+	@Test(expected = FormatException.class)
+	public void testRejectsLinkWithUnknownFormatVersion() throws Exception {
+		String link = encodeLink(FORMAT_VERSION + 1);
+		pendingContactFactory.createPendingContact(link, alias);
+	}
+
+	@Test(expected = FormatException.class)
+	public void testRejectsLinkWithInvalidPublicKey() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).getAgreementKeyParser();
+			will(returnValue(keyParser));
+			oneOf(keyParser).parsePublicKey(with(equal(publicKeyBytes)));
+			will(throwException(new GeneralSecurityException()));
+		}});
+
+		pendingContactFactory.createPendingContact(encodeLink(), alias);
+	}
+
+	@Test
+	public void testAcceptsValidLinkWithoutPrefix() throws Exception {
+		testAcceptsValidLink(encodeLink());
+	}
+
+	@Test
+	public void testAcceptsValidLinkWithPrefix() throws Exception {
+		testAcceptsValidLink("briar://" + encodeLink());
+	}
+
+	@Test
+	public void testAcceptsValidLinkWithRubbish() throws Exception {
+		testAcceptsValidLink("before " + encodeLink() + " after");
+	}
+
+	@Test
+	public void testAcceptsValidLinkWithPrefixAndRubbish() throws Exception {
+		testAcceptsValidLink("before briar://" + encodeLink() + " after");
+	}
+
+	private void testAcceptsValidLink(String link) throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).getAgreementKeyParser();
+			will(returnValue(keyParser));
+			oneOf(keyParser).parsePublicKey(with(equal(publicKeyBytes)));
+			will(returnValue(publicKey));
+			allowing(publicKey).getEncoded();
+			will(returnValue(publicKeyBytes));
+			oneOf(crypto).hash(ID_LABEL, publicKeyBytes);
+			will(returnValue(idBytes));
+			oneOf(clock).currentTimeMillis();
+			will(returnValue(timestamp));
+		}});
+
+		PendingContact p =
+				pendingContactFactory.createPendingContact(link, alias);
+		assertArrayEquals(idBytes, p.getId().getBytes());
+		assertArrayEquals(publicKeyBytes, p.getPublicKey());
+		assertEquals(alias, p.getAlias());
+		assertEquals(WAITING_FOR_CONNECTION, p.getState());
+		assertEquals(timestamp, p.getTimestamp());
+	}
+
+	private String encodeLink() {
+		return encodeLink(FORMAT_VERSION);
+	}
+
+	private String encodeLink(int formatVersion) {
+		byte[] rawLink = new byte[RAW_LINK_BYTES];
+		rawLink[0] = (byte) formatVersion;
+		arraycopy(publicKeyBytes, 0, rawLink, 1, publicKeyBytes.length);
+		String base32 = Base32.encode(rawLink).toLowerCase();
+		assertEquals(BASE32_LINK_BYTES, base32.length());
+		return base32;
+	}
+}
-- 
GitLab