diff --git a/src/main/java/io/kamax/mxisd/crypto/SignatureManager.java b/src/main/java/io/kamax/mxisd/crypto/SignatureManager.java
index bcfdcfa..99d0470 100644
--- a/src/main/java/io/kamax/mxisd/crypto/SignatureManager.java
+++ b/src/main/java/io/kamax/mxisd/crypto/SignatureManager.java
@@ -20,12 +20,45 @@
package io.kamax.mxisd.crypto;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import io.kamax.matrix.event.EventKey;
+import io.kamax.matrix.json.MatrixJson;
import java.nio.charset.StandardCharsets;
+import java.util.Objects;
public interface SignatureManager {
+ /**
+ * Sign the message and add the signature to the signatures key.
+ *
+ * If the key does not exist yet, it is created. If the key exist, the produced signature will be merged with any
+ * existing ones.
+ *
+ * @param domain The domain under which the signature should be added
+ * @param message The message to sign and add the produced signature to
+ * @return The provided message with the new signature
+ * @throws IllegalArgumentException If the signatures value is not a JSON object
+ */
+ default JsonObject signMessageGson(String domain, JsonObject message) throws IllegalArgumentException {
+ JsonElement signEl = message.remove(EventKey.Signatures.get());
+ JsonObject oldSigns = new JsonObject();
+ if (!Objects.isNull(signEl)) {
+ if (!signEl.isJsonObject()) {
+ throw new IllegalArgumentException("Message contains a signatures key that is not a JSON object value");
+ }
+
+ oldSigns = signEl.getAsJsonObject();
+ }
+
+ JsonObject newSigns = signMessageGson(domain, MatrixJson.encodeCanonical(message));
+ oldSigns.entrySet().forEach(entry -> newSigns.add(entry.getKey(), entry.getValue()));
+ message.add(EventKey.Signatures.get(), newSigns);
+
+ return message;
+ }
+
/**
* Sign the message and produce a signatures object that can directly be added to the object being signed.
*
diff --git a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java
index d81d38c..87cf6f1 100644
--- a/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java
+++ b/src/main/java/io/kamax/mxisd/http/undertow/handler/identity/v1/SingleLookupHandler.java
@@ -21,9 +21,7 @@
package io.kamax.mxisd.http.undertow.handler.identity.v1;
import com.google.gson.JsonObject;
-import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.GsonUtil;
-import io.kamax.matrix.json.MatrixJson;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.config.ServerConfig;
import io.kamax.mxisd.crypto.SignatureManager;
@@ -73,11 +71,8 @@ public class SingleLookupHandler extends LookupHandler {
respondJson(exchange, "{}");
} else {
SingleLookupReply lookup = lookupOpt.get();
-
- // FIXME signing should be done in the business model, not in the controller
JsonObject obj = GsonUtil.makeObj(new SingeLookupReplyJson(lookup));
- obj.add(EventKey.Signatures.get(), signMgr.signMessageGson(cfg.getName(), MatrixJson.encodeCanonical(obj)));
-
+ signMgr.signMessageGson(cfg.getName(), obj);
respondJson(exchange, obj);
}
}
diff --git a/src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java b/src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java
index 06d2fed..b48a723 100644
--- a/src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java
+++ b/src/test/java/io/kamax/mxisd/test/crypto/SignatureManagerTest.java
@@ -21,6 +21,7 @@
package io.kamax.mxisd.test.crypto;
import com.google.gson.JsonObject;
+import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.MatrixJson;
import io.kamax.mxisd.crypto.Signature;
@@ -36,10 +37,14 @@ import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class SignatureManagerTest {
+ private static final String lookupData = "{\n" + " \"not_before\": 0,\n" + " \"address\": \"mxisd-federation-test@kamax.io\",\n"
+ + " \"medium\": \"email\",\n" + " \"mxid\": \"@mxisd-lookup-test:kamax.io\",\n"
+ + " \"not_after\": 253402300799000,\n" + " \"ts\": 1523482030147\n" + "}";
private static SignatureManager signMgr;
private static SignatureManager build(String keySeed) {
@@ -98,12 +103,19 @@ public class SignatureManagerTest {
@Test
public void onIdentityLookup() {
- String value = MatrixJson.encodeCanonical("{\n" + " \"address\": \"mxisd-federation-test@kamax.io\",\n"
- + " \"medium\": \"email\",\n" + " \"mxid\": \"@mxisd-lookup-test:kamax.io\",\n"
- + " \"not_after\": 253402300799000,\n" + " \"not_before\": 0,\n" + " \"ts\": 1523482030147\n" + "}");
-
+ String value = MatrixJson.encodeCanonical(lookupData);
String sign = "ObKA4PNQh2g6c7Yo2QcTcuDgIwhknG7ZfqmNYzbhrbLBOqZomU22xX9raufN2Y3ke1FXsDqsGs7WBDodmzZJCg";
testSign(value, sign);
}
+ @Test
+ public void onIdentityLookupFull() {
+ JsonObject data = GsonUtil.parseObj(lookupData);
+ signMgr.signMessageGson("localhost", data);
+ JsonObject signatures = EventKey.Signatures.getObj(data);
+ JsonObject domainSign = GsonUtil.getObj(signatures, "localhost");
+ String sign = GsonUtil.getStringOrThrow(domainSign, "ed25519:0");
+ assertEquals(sign, "ObKA4PNQh2g6c7Yo2QcTcuDgIwhknG7ZfqmNYzbhrbLBOqZomU22xX9raufN2Y3ke1FXsDqsGs7WBDodmzZJCg");
+ }
+
}