Store ephemeral key in invite and add support for /sign-ed25519
This commit is contained in:
@@ -91,6 +91,7 @@ public class HttpMxisd {
|
||||
.get(SessionTpidGetValidatedHandler.Path, SaneHandler.around(new SessionTpidGetValidatedHandler(m.getSession())))
|
||||
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvitationManager())))
|
||||
.post(SessionTpidUnbindHandler.Path, SaneHandler.around(new SessionTpidUnbindHandler(m.getSession())))
|
||||
.post(SignEd25519Handler.Path, SaneHandler.around(new SignEd25519Handler(m.getConfig(), m.getInvitationManager(), m.getSign())))
|
||||
|
||||
// Profile endpoints
|
||||
.get(ProfileHandler.Path, SaneHandler.around(new ProfileHandler(m.getProfile())))
|
||||
|
@@ -106,7 +106,7 @@ public class Mxisd {
|
||||
pMgr = new ProfileManager(ProfileProviders.get(), clientDns, httpClient);
|
||||
notifMgr = new NotificationManager(cfg.getNotification(), NotificationHandlers.get());
|
||||
sessMgr = new SessionManager(cfg.getSession(), cfg.getMatrix(), store, notifMgr, idStrategy, httpClient);
|
||||
invMgr = new InvitationManager(cfg, store, idStrategy, signMgr, fedDns, notifMgr);
|
||||
invMgr = new InvitationManager(cfg, store, idStrategy, keyMgr, signMgr, fedDns, notifMgr);
|
||||
authMgr = new AuthManager(cfg, AuthProviders.get(), idStrategy, invMgr, clientDns, httpClient);
|
||||
dirMgr = new DirectoryManager(cfg.getDirectory(), clientDns, httpClient, DirectoryProviders.get());
|
||||
asHander = new AppSvcManager(cfg, store, pMgr, notifMgr, synapse);
|
||||
|
@@ -22,8 +22,12 @@ package io.kamax.mxisd.exception;
|
||||
|
||||
public class ObjectNotFoundException extends RuntimeException {
|
||||
|
||||
public ObjectNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ObjectNotFoundException(String type, String id) {
|
||||
super(type + " with ID " + id + " does not exist");
|
||||
this(type + " with ID " + id + " does not exist");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2019 Kamax Sarl
|
||||
*
|
||||
* https://www.kamax.io/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.matrix.json.MatrixJson;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.http.IsAPIv1;
|
||||
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
|
||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||
import io.kamax.mxisd.invitation.InvitationManager;
|
||||
import io.kamax.mxisd.storage.crypto.SignatureManager;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SignEd25519Handler extends BasicHttpHandler {
|
||||
|
||||
public static final String Path = IsAPIv1.Base + "/sign-ed25519";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SignEd25519Handler.class);
|
||||
|
||||
private final MxisdConfig cfg;
|
||||
private final InvitationManager invMgr;
|
||||
private final SignatureManager signMgr;
|
||||
|
||||
public SignEd25519Handler(MxisdConfig cfg, InvitationManager invMgr, SignatureManager signMgr) {
|
||||
this.cfg = cfg;
|
||||
this.invMgr = invMgr;
|
||||
this.signMgr = signMgr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(HttpServerExchange exchange) {
|
||||
JsonObject body = parseJsonObject(exchange);
|
||||
|
||||
_MatrixID mxid = MatrixID.asAcceptable(GsonUtil.getStringOrThrow(body, "mxid"));
|
||||
String token = GsonUtil.getStringOrThrow(body, "token");
|
||||
String privKey = GsonUtil.getStringOrThrow(body, "private_key");
|
||||
|
||||
IThreePidInviteReply reply = invMgr.getInvite(token, privKey);
|
||||
_MatrixID sender = reply.getInvite().getSender();
|
||||
|
||||
JsonObject res = new JsonObject();
|
||||
res.addProperty("token", token);
|
||||
res.addProperty("sender", sender.getId());
|
||||
res.addProperty("mxid", mxid.getId());
|
||||
res.add("signatures", signMgr.signMessageGson(cfg.getServer().getName(), MatrixJson.encodeCanonical(res)));
|
||||
|
||||
log.info("Signed data for invite using token {}", token);
|
||||
respondJson(exchange, res);
|
||||
}
|
||||
|
||||
}
|
@@ -20,6 +20,8 @@
|
||||
|
||||
package io.kamax.mxisd.invitation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IThreePidInviteReply {
|
||||
|
||||
String getId();
|
||||
@@ -30,4 +32,6 @@ public interface IThreePidInviteReply {
|
||||
|
||||
String getDisplayName();
|
||||
|
||||
List<String> getPublicKeys();
|
||||
|
||||
}
|
||||
|
@@ -30,16 +30,17 @@ import io.kamax.mxisd.config.ServerConfig;
|
||||
import io.kamax.mxisd.dns.FederationDnsOverwrite;
|
||||
import io.kamax.mxisd.exception.BadRequestException;
|
||||
import io.kamax.mxisd.exception.MappingAlreadyExistsException;
|
||||
import io.kamax.mxisd.exception.ObjectNotFoundException;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.lookup.ThreePidMapping;
|
||||
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
||||
import io.kamax.mxisd.notification.NotificationManager;
|
||||
import io.kamax.mxisd.storage.IStorage;
|
||||
import io.kamax.mxisd.storage.crypto.SignatureManager;
|
||||
import io.kamax.mxisd.storage.crypto.*;
|
||||
import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
@@ -72,6 +73,7 @@ public class InvitationManager {
|
||||
private ServerConfig srvCfg;
|
||||
private IStorage storage;
|
||||
private LookupStrategy lookupMgr;
|
||||
private KeyManager keyMgr;
|
||||
private SignatureManager signMgr;
|
||||
private FederationDnsOverwrite dns;
|
||||
private NotificationManager notifMgr;
|
||||
@@ -85,6 +87,7 @@ public class InvitationManager {
|
||||
MxisdConfig mxisdCfg,
|
||||
IStorage storage,
|
||||
LookupStrategy lookupMgr,
|
||||
KeyManager keyMgr,
|
||||
SignatureManager signMgr,
|
||||
FederationDnsOverwrite dns,
|
||||
NotificationManager notifMgr
|
||||
@@ -93,6 +96,7 @@ public class InvitationManager {
|
||||
this.srvCfg = mxisdCfg.getServer();
|
||||
this.storage = storage;
|
||||
this.lookupMgr = lookupMgr;
|
||||
this.keyMgr = keyMgr;
|
||||
this.signMgr = signMgr;
|
||||
this.dns = dns;
|
||||
this.notifMgr = notifMgr;
|
||||
@@ -109,7 +113,7 @@ public class InvitationManager {
|
||||
io.getProperties()
|
||||
);
|
||||
|
||||
ThreePidInviteReply reply = new ThreePidInviteReply(getId(invite), invite, io.getToken(), "");
|
||||
ThreePidInviteReply reply = new ThreePidInviteReply(getId(invite), invite, io.getToken(), "", Collections.emptyList());
|
||||
invitations.put(reply.getId(), reply);
|
||||
});
|
||||
|
||||
@@ -221,7 +225,7 @@ public class InvitationManager {
|
||||
log.info("Invite is already pending for {}:{}, returning data", invitation.getMedium(), invitation.getAddress());
|
||||
if (!StringUtils.equals(invitation.getRoomId(), reply.getInvite().getRoomId())) {
|
||||
log.info("Sending new notification as new invite room {} is different from the original {}", invitation.getRoomId(), reply.getInvite().getRoomId());
|
||||
notifMgr.sendForReply(new ThreePidInviteReply(reply.getId(), invitation, reply.getToken(), reply.getDisplayName()));
|
||||
notifMgr.sendForReply(new ThreePidInviteReply(reply.getId(), invitation, reply.getToken(), reply.getDisplayName(), reply.getPublicKeys()));
|
||||
} else {
|
||||
// FIXME we should check attempt and send if bigger
|
||||
}
|
||||
@@ -236,8 +240,20 @@ public class InvitationManager {
|
||||
|
||||
String token = RandomStringUtils.randomAlphanumeric(64);
|
||||
String displayName = invitation.getAddress().substring(0, 3) + "...";
|
||||
KeyIdentifier pKeyId = keyMgr.getServerSigningKey().getId();
|
||||
KeyIdentifier eKeyId = keyMgr.generateKey(KeyType.Ephemeral);
|
||||
|
||||
reply = new ThreePidInviteReply(invId, invitation, token, displayName);
|
||||
String pPubKey = keyMgr.getPublicKeyBase64(pKeyId);
|
||||
String ePubKey = keyMgr.getPublicKeyBase64(eKeyId);
|
||||
|
||||
invitation.getProperties().put("p_key_algo", pKeyId.getAlgorithm());
|
||||
invitation.getProperties().put("p_key_serial", pKeyId.getSerial());
|
||||
invitation.getProperties().put("p_key_public", pPubKey);
|
||||
invitation.getProperties().put("e_key_algo", eKeyId.getAlgorithm());
|
||||
invitation.getProperties().put("e_key_serial", eKeyId.getSerial());
|
||||
invitation.getProperties().put("e_key_public", ePubKey);
|
||||
|
||||
reply = new ThreePidInviteReply(invId, invitation, token, displayName, Arrays.asList(pPubKey, ePubKey));
|
||||
|
||||
log.info("Performing invite to {}:{}", invitation.getMedium(), invitation.getAddress());
|
||||
notifMgr.sendForReply(reply);
|
||||
@@ -270,6 +286,28 @@ public class InvitationManager {
|
||||
}
|
||||
}
|
||||
|
||||
public IThreePidInviteReply getInvite(String token, String privKey) {
|
||||
for (IThreePidInviteReply reply : invitations.values()) {
|
||||
if (StringUtils.equals(reply.getToken(), token)) {
|
||||
String algo = reply.getInvite().getProperties().get("e_key_algo");
|
||||
String serial = reply.getInvite().getProperties().get("e_key_serial");
|
||||
|
||||
if (StringUtils.isAnyBlank(algo, serial)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String storedPrivKey = keyMgr.getKey(new GenericKeyIdentifier(KeyType.Ephemeral, algo, serial)).getPrivateKeyBase64();
|
||||
if (!StringUtils.equals(storedPrivKey, privKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ObjectNotFoundException("No invite with such token and/or private key");
|
||||
}
|
||||
|
||||
private void publishMapping(IThreePidInviteReply reply, String mxid) {
|
||||
String medium = reply.getInvite().getMedium();
|
||||
String address = reply.getInvite().getAddress();
|
||||
|
@@ -20,18 +20,24 @@
|
||||
|
||||
package io.kamax.mxisd.invitation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ThreePidInviteReply implements IThreePidInviteReply {
|
||||
|
||||
private String id;
|
||||
private IThreePidInvite invite;
|
||||
private String token;
|
||||
private String displayName;
|
||||
private List<String> publicKeys;
|
||||
|
||||
public ThreePidInviteReply(String id, IThreePidInvite invite, String token, String displayName) {
|
||||
public ThreePidInviteReply(String id, IThreePidInvite invite, String token, String displayName, List<String> publicKeys) {
|
||||
this.id = id;
|
||||
this.invite = invite;
|
||||
this.token = token;
|
||||
this.displayName = displayName;
|
||||
this.publicKeys = Collections.unmodifiableList(new ArrayList<>(publicKeys));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,4 +60,9 @@ public class ThreePidInviteReply implements IThreePidInviteReply {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPublicKeys() {
|
||||
return publicKeys;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user