Add lookup and invite commands to the admin AS interface

This commit is contained in:
Max Dor
2019-03-04 00:02:13 +01:00
parent de840b9d00
commit 1dce59a02e
13 changed files with 253 additions and 67 deletions

View File

@@ -145,6 +145,9 @@ dependencies {
// HTTP server // HTTP server
compile 'io.undertow:undertow-core:2.0.16.Final' compile 'io.undertow:undertow-core:2.0.16.Final'
// Command parser for AS interface
implementation 'commons-cli:commons-cli:1.4'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'com.github.tomakehurst:wiremock:2.8.0' testCompile 'com.github.tomakehurst:wiremock:2.8.0'

View File

@@ -72,7 +72,7 @@ public class HttpMxisd {
HttpHandler asTxnHandler = SaneHandler.around(new AsTransactionHandler(m.getAs())); HttpHandler asTxnHandler = SaneHandler.around(new AsTransactionHandler(m.getAs()));
HttpHandler asNotFoundHandler = SaneHandler.around(new AsNotFoundHandler(m.getAs())); HttpHandler asNotFoundHandler = SaneHandler.around(new AsNotFoundHandler(m.getAs()));
HttpHandler storeInvHandler = SaneHandler.around(new StoreInviteHandler(m.getConfig().getServer(), m.getInvitationManager(), m.getKeyManager())); HttpHandler storeInvHandler = SaneHandler.around(new StoreInviteHandler(m.getConfig().getServer(), m.getInvite(), m.getKeyManager()));
HttpHandler sessValidateHandler = SaneHandler.around(new SessionValidateHandler(m.getSession(), m.getConfig().getServer(), m.getConfig().getView())); HttpHandler sessValidateHandler = SaneHandler.around(new SessionValidateHandler(m.getSession(), m.getConfig().getServer(), m.getConfig().getView()));
httpSrv = Undertow.builder().addHttpListener(m.getConfig().getServer().getPort(), "0.0.0.0").setHandler(Handlers.routing() httpSrv = Undertow.builder().addHttpListener(m.getConfig().getServer().getPort(), "0.0.0.0").setHandler(Handlers.routing()
@@ -106,9 +106,9 @@ public class HttpMxisd {
.get(SessionValidateHandler.Path, sessValidateHandler) .get(SessionValidateHandler.Path, sessValidateHandler)
.post(SessionValidateHandler.Path, sessValidateHandler) .post(SessionValidateHandler.Path, sessValidateHandler)
.get(SessionTpidGetValidatedHandler.Path, SaneHandler.around(new SessionTpidGetValidatedHandler(m.getSession()))) .get(SessionTpidGetValidatedHandler.Path, SaneHandler.around(new SessionTpidGetValidatedHandler(m.getSession())))
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvitationManager()))) .post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvite())))
.post(SessionTpidUnbindHandler.Path, SaneHandler.around(new SessionTpidUnbindHandler(m.getSession()))) .post(SessionTpidUnbindHandler.Path, SaneHandler.around(new SessionTpidUnbindHandler(m.getSession())))
.post(SignEd25519Handler.Path, SaneHandler.around(new SignEd25519Handler(m.getConfig(), m.getInvitationManager(), m.getSign()))) .post(SignEd25519Handler.Path, SaneHandler.around(new SignEd25519Handler(m.getConfig(), m.getInvite(), m.getSign())))
// Profile endpoints // Profile endpoints
.get(ProfileHandler.Path, SaneHandler.around(new ProfileHandler(m.getProfile()))) .get(ProfileHandler.Path, SaneHandler.around(new ProfileHandler(m.getProfile())))
@@ -118,7 +118,7 @@ public class HttpMxisd {
.post(Register3pidRequestTokenHandler.Path, SaneHandler.around(new Register3pidRequestTokenHandler(m.getReg(), m.getClientDns(), m.getHttpClient()))) .post(Register3pidRequestTokenHandler.Path, SaneHandler.around(new Register3pidRequestTokenHandler(m.getReg(), m.getClientDns(), m.getHttpClient())))
// Invite endpoints // Invite endpoints
.post(RoomInviteHandler.Path, SaneHandler.around(new RoomInviteHandler(m.getHttpClient(), m.getClientDns(), m.getInvitationManager()))) .post(RoomInviteHandler.Path, SaneHandler.around(new RoomInviteHandler(m.getHttpClient(), m.getClientDns(), m.getInvite())))
// Application Service endpoints // Application Service endpoints
.get(AsUserHandler.Path, asUserHandler) .get(AsUserHandler.Path, asUserHandler)

View File

@@ -85,6 +85,9 @@ public class Mxisd {
private NotificationManager notifMgr; private NotificationManager notifMgr;
private RegistrationManager regMgr; private RegistrationManager regMgr;
// HS-specific classes
private Synapse synapse;
public Mxisd(MxisdConfig cfg) { public Mxisd(MxisdConfig cfg) {
this.cfg = cfg.build(); this.cfg = cfg.build();
} }
@@ -104,7 +107,7 @@ public class Mxisd {
signMgr = CryptoFactory.getSignatureManager(keyMgr); signMgr = CryptoFactory.getSignatureManager(keyMgr);
clientDns = new ClientDnsOverwrite(cfg.getDns().getOverwrite()); clientDns = new ClientDnsOverwrite(cfg.getDns().getOverwrite());
FederationDnsOverwrite fedDns = new FederationDnsOverwrite(cfg.getDns().getOverwrite()); FederationDnsOverwrite fedDns = new FederationDnsOverwrite(cfg.getDns().getOverwrite());
Synapse synapse = new Synapse(cfg.getSynapseSql()); synapse = new Synapse(cfg.getSynapseSql());
BridgeFetcher bridgeFetcher = new BridgeFetcher(cfg.getLookup().getRecursive().getBridge(), srvFetcher); BridgeFetcher bridgeFetcher = new BridgeFetcher(cfg.getLookup().getRecursive().getBridge(), srvFetcher);
ServiceLoader.load(IdentityStoreSupplier.class).iterator().forEachRemaining(p -> p.accept(this)); ServiceLoader.load(IdentityStoreSupplier.class).iterator().forEachRemaining(p -> p.accept(this));
@@ -118,7 +121,7 @@ public class Mxisd {
authMgr = new AuthManager(cfg, AuthProviders.get(), idStrategy, invMgr, clientDns, httpClient); authMgr = new AuthManager(cfg, AuthProviders.get(), idStrategy, invMgr, clientDns, httpClient);
dirMgr = new DirectoryManager(cfg.getDirectory(), clientDns, httpClient, DirectoryProviders.get()); dirMgr = new DirectoryManager(cfg.getDirectory(), clientDns, httpClient, DirectoryProviders.get());
regMgr = new RegistrationManager(cfg.getRegister(), httpClient, clientDns, invMgr); regMgr = new RegistrationManager(cfg.getRegister(), httpClient, clientDns, invMgr);
asHander = new AppSvcManager(cfg, store, pMgr, notifMgr, synapse); asHander = new AppSvcManager(this);
} }
public MxisdConfig getConfig() { public MxisdConfig getConfig() {
@@ -141,7 +144,7 @@ public class Mxisd {
return keyMgr; return keyMgr;
} }
public InvitationManager getInvitationManager() { public InvitationManager getInvite() {
return invMgr; return invMgr;
} }
@@ -181,6 +184,14 @@ public class Mxisd {
return notifMgr; return notifMgr;
} }
public IStorage getStore() {
return store;
}
public Synapse getSynapse() {
return synapse;
}
public void start() { public void start() {
build(); build();
} }

View File

@@ -27,18 +27,16 @@ import io.kamax.matrix.client.MatrixClientContext;
import io.kamax.matrix.client.as.MatrixApplicationServiceClient; import io.kamax.matrix.client.as.MatrixApplicationServiceClient;
import io.kamax.matrix.event.EventKey; import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.as.processor.event.EventTypeProcessor; import io.kamax.mxisd.as.processor.event.EventTypeProcessor;
import io.kamax.mxisd.as.processor.event.MembershipEventProcessor; import io.kamax.mxisd.as.processor.event.MembershipEventProcessor;
import io.kamax.mxisd.as.processor.event.MessageEventProcessor; import io.kamax.mxisd.as.processor.event.MessageEventProcessor;
import io.kamax.mxisd.as.registration.SynapseRegistrationYaml; import io.kamax.mxisd.as.registration.SynapseRegistrationYaml;
import io.kamax.mxisd.backend.sql.synapse.Synapse;
import io.kamax.mxisd.config.AppServiceConfig; import io.kamax.mxisd.config.AppServiceConfig;
import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import io.kamax.mxisd.exception.HttpMatrixException; import io.kamax.mxisd.exception.HttpMatrixException;
import io.kamax.mxisd.exception.NotAllowedException; import io.kamax.mxisd.exception.NotAllowedException;
import io.kamax.mxisd.notification.NotificationManager;
import io.kamax.mxisd.profile.ProfileManager;
import io.kamax.mxisd.storage.IStorage; import io.kamax.mxisd.storage.IStorage;
import io.kamax.mxisd.storage.ormlite.dao.ASTransactionDao; import io.kamax.mxisd.storage.ormlite.dao.ASTransactionDao;
import io.kamax.mxisd.util.GsonParser; import io.kamax.mxisd.util.GsonParser;
@@ -72,9 +70,9 @@ public class AppSvcManager {
private Map<String, EventTypeProcessor> processors = new HashMap<>(); private Map<String, EventTypeProcessor> processors = new HashMap<>();
private Map<String, CompletableFuture<String>> transactionsInProgress = new ConcurrentHashMap<>(); private Map<String, CompletableFuture<String>> transactionsInProgress = new ConcurrentHashMap<>();
public AppSvcManager(MxisdConfig mxisdCfg, IStorage store, ProfileManager profiler, NotificationManager notif, Synapse synapse) { public AppSvcManager(Mxisd m) {
this.cfg = mxisdCfg.getAppsvc(); this.cfg = m.getConfig().getAppsvc();
this.store = store; this.store = m.getStore();
/* /*
We process the configuration to make sure all is fine and setting default values if needed We process the configuration to make sure all is fine and setting default values if needed
@@ -129,15 +127,15 @@ public class AppSvcManager {
} }
MatrixClientContext mxContext = new MatrixClientContext(); MatrixClientContext mxContext = new MatrixClientContext();
mxContext.setDomain(mxisdCfg.getMatrix().getDomain()); mxContext.setDomain(m.getConfig().getMatrix().getDomain());
mxContext.setToken(cfg.getEndpoint().getToHS().getToken()); mxContext.setToken(cfg.getEndpoint().getToHS().getToken());
mxContext.setHsBaseUrl(cfg.getEndpoint().getToHS().getUrl()); mxContext.setHsBaseUrl(cfg.getEndpoint().getToHS().getUrl());
client = new MatrixApplicationServiceClient(mxContext); client = new MatrixApplicationServiceClient(mxContext);
processors.put("m.room.member", new MembershipEventProcessor(client, mxisdCfg, profiler, notif, synapse)); processors.put("m.room.member", new MembershipEventProcessor(client, m));
processors.put("m.room.message", new MessageEventProcessor(client)); processors.put("m.room.message", new MessageEventProcessor(m, client));
processSynapseConfig(mxisdCfg); processSynapseConfig(m.getConfig());
} }
private void processSynapseConfig(MxisdConfig cfg) { private void processSynapseConfig(MxisdConfig cfg) {

View File

@@ -23,9 +23,10 @@ package io.kamax.mxisd.as.processor.command;
import io.kamax.matrix.client._MatrixClient; import io.kamax.matrix.client._MatrixClient;
import io.kamax.matrix.hs._MatrixRoom; import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
import org.apache.commons.cli.CommandLine;
public interface CommandProcessor { public interface CommandProcessor {
void process(Mxisd m, _MatrixClient client, _MatrixRoom room, String command, String[] arguments); void process(Mxisd m, _MatrixClient client, _MatrixRoom room, CommandLine cmdLine);
} }

View File

@@ -23,31 +23,80 @@ package io.kamax.mxisd.as.processor.command;
import io.kamax.matrix.client._MatrixClient; import io.kamax.matrix.client._MatrixClient;
import io.kamax.matrix.hs._MatrixRoom; import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.invitation.IThreePidInviteReply;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
import java.util.List;
public class InviteCommandProcessor implements CommandProcessor { public class InviteCommandProcessor implements CommandProcessor {
public static final String Command = "invite"; public static final String Command = "invite";
@Override @Override
public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, String command, String[] arguments) { public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, CommandLine cmdLine) {
if (arguments.length < 1) { if (cmdLine.getArgs().length < 2) {
room.sendText(buildHelp()); room.sendNotice(buildHelp());
}
String subcmd = arguments[0];
String response;
if (StringUtils.equals("list", subcmd)) {
response = buildError("This command is not supported yet", false);
} else if (StringUtils.endsWith("show", subcmd)) {
response = buildError("This command is not supported yet", false);
} else if (StringUtils.equals("revoke", subcmd)) {
response = buildError("This command is not supported yet", false);
} else { } else {
response = buildError("Unknown command: " + subcmd, true); String arg = cmdLine.getArgList().get(1);
} String response;
if (StringUtils.equals("list", arg)) {
room.sendText(response); StrBuilder b = new StrBuilder();
List<IThreePidInviteReply> invites = m.getInvite().listInvites();
if (invites.isEmpty()) {
b.appendln("No invites!");
response = b.toString();
} else {
b.appendln("Invites:");
for (IThreePidInviteReply invite : invites) {
b.appendNewLine().append("ID: ").append(invite.getId());
b.appendNewLine().append("Room: ").append(invite.getInvite().getRoomId());
b.appendNewLine().append("Medium: ").append(invite.getInvite().getMedium());
b.appendNewLine().append("Address: ").append(invite.getInvite().getAddress());
b.appendNewLine();
}
response = b.appendNewLine().append("Total: " + invites.size()).toString();
}
} else if (StringUtils.equals("show", arg)) {
if (cmdLine.getArgList().size() < 3) {
response = buildHelp();
} else {
String id = cmdLine.getArgList().get(2);
IThreePidInviteReply invite = m.getInvite().getInvite(id);
StrBuilder b = new StrBuilder();
b.appendln("Details for Invitation #" + id);
b.appendNewLine().append("Room: ").append(invite.getInvite().getRoomId());
b.appendNewLine().append("Sender: ").append(invite.getInvite().getSender().toString());
b.appendNewLine().append("Medium: ").append(invite.getInvite().getMedium());
b.appendNewLine().append("Address: ").append(invite.getInvite().getAddress());
b.appendNewLine().append("Display name: ").append(invite.getDisplayName());
b.appendNewLine().appendNewLine().append("Properties:");
invite.getInvite().getProperties().forEach((k, v) -> {
b.appendNewLine().append("\t").append(k).append("=").append(v);
});
b.appendNewLine();
response = b.toString();
}
} else if (StringUtils.equals("revoke", arg)) {
if (cmdLine.getArgList().size() < 3) {
response = buildHelp();
} else {
m.getInvite().expireInvite(cmdLine.getArgList().get(2));
response = "OK";
}
} else {
response = buildError("Unknown invite action: " + arg, true);
}
room.sendNotice(response);
}
} }
private String buildError(String message, boolean showHelp) { private String buildError(String message, boolean showHelp) {
@@ -61,8 +110,8 @@ public class InviteCommandProcessor implements CommandProcessor {
private String buildHelp() { private String buildHelp() {
return "Available actions:\n\n" + return "Available actions:\n\n" +
"list - List invites\n" + "list - List invites\n" +
"show - Show detailed info about a specific invite\n" + "show ID - Show detailed info about a specific invite\n" +
"revoke - Revoke a pending invite by resolving it to the configured Expiration user\n"; "revoke ID - Revoke a pending invite by resolving it to the configured Expiration user\n";
} }
} }

View File

@@ -0,0 +1,73 @@
/*
* 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.as.processor.command;
import io.kamax.matrix.client._MatrixClient;
import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.lookup.SingleLookupReply;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.lang.text.StrBuilder;
import org.apache.commons.lang3.StringUtils;
import java.util.Optional;
public class LookupCommandProcessor implements CommandProcessor {
public static final String Command = "lookup";
@Override
public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, CommandLine cmdLine) {
if (cmdLine.getArgList().size() != 3) {
room.sendNotice(getUsage());
return;
}
String medium = cmdLine.getArgList().get(1);
String address = cmdLine.getArgList().get(2);
if (StringUtils.isAnyBlank(medium, address)) {
room.sendNotice(getUsage());
return;
}
room.sendNotice("Processing...");
Optional<SingleLookupReply> r = m.getIdentity().find(medium, address, true);
if (!r.isPresent()) {
room.sendNotice("No result");
return;
}
SingleLookupReply lookup = r.get();
StrBuilder b = new StrBuilder();
b.append("Result for 3PID lookup on ").append(medium).append(" ").appendln(address).appendNewLine();
b.append("Matrix ID: ").appendln(lookup.getMxid().getId());
b.appendln("Validity:")
.append("\tNot Before: ").appendln(lookup.getNotBefore())
.append("\tNot After: ").appendln(lookup.getNotAfter());
room.sendNotice(b.toString());
}
public String getUsage() {
return "lookup MEDIUM ADDRESS";
}
}

View File

@@ -23,14 +23,15 @@ package io.kamax.mxisd.as.processor.command;
import io.kamax.matrix.client._MatrixClient; import io.kamax.matrix.client._MatrixClient;
import io.kamax.matrix.hs._MatrixRoom; import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
import org.apache.commons.cli.CommandLine;
public class PingCommandProcessor implements CommandProcessor { public class PingCommandProcessor implements CommandProcessor {
public static final String Command = "ping"; public static final String Command = "ping";
@Override @Override
public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, String command, String[] arguments) { public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, CommandLine cmdLine) {
room.sendText("Pong!"); room.sendNotice("Pong!");
} }
} }

View File

@@ -28,6 +28,7 @@ import io.kamax.matrix._ThreePid;
import io.kamax.matrix.client.as.MatrixApplicationServiceClient; import io.kamax.matrix.client.as.MatrixApplicationServiceClient;
import io.kamax.matrix.event.EventKey; import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.hs._MatrixRoom; import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.backend.sql.synapse.Synapse; import io.kamax.mxisd.backend.sql.synapse.Synapse;
import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.invitation.IMatrixIdInvite; import io.kamax.mxisd.invitation.IMatrixIdInvite;
@@ -38,7 +39,6 @@ import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -57,16 +57,13 @@ public class MembershipEventProcessor implements EventTypeProcessor {
public MembershipEventProcessor( public MembershipEventProcessor(
MatrixApplicationServiceClient client, MatrixApplicationServiceClient client,
MxisdConfig cfg, Mxisd m
ProfileManager profiler,
NotificationManager notif,
Synapse synapse
) { ) {
this.client = client; this.client = client;
this.cfg = cfg; this.cfg = m.getConfig();
this.profiler = profiler; this.profiler = m.getProfile();
this.notif = notif; this.notif = m.getNotif();
this.synapse = synapse; this.synapse = m.getSynapse();
} }
@Override @Override
@@ -121,8 +118,8 @@ public class MembershipEventProcessor implements EventTypeProcessor {
} }
private void processForMainUser(String roomId, _MatrixID sender) { private void processForMainUser(String roomId, _MatrixID sender) {
List<String> roles = profiler.getRoles(sender); boolean isAllowed = profiler.hasAnyRole(sender, cfg.getAppsvc().getFeature().getAdmin().getAllowedRoles());
if (Collections.disjoint(roles, cfg.getAppsvc().getFeature().getAdmin().getAllowedRoles())) { if (!isAllowed) {
log.info("Sender does not have any of the required roles, denying"); log.info("Sender does not have any of the required roles, denying");
client.getRoom(roomId).tryLeave().ifPresent(err -> { client.getRoom(roomId).tryLeave().ifPresent(err -> {
log.warn("Could not decline invite to room {}: {} - {}", roomId, err.getErrcode(), err.getError()); log.warn("Could not decline invite to room {}: {} - {}", roomId, err.getErrcode(), err.getError());

View File

@@ -26,9 +26,13 @@ import io.kamax.matrix._MatrixUserProfile;
import io.kamax.matrix.client.as.MatrixApplicationServiceClient; import io.kamax.matrix.client.as.MatrixApplicationServiceClient;
import io.kamax.matrix.hs._MatrixRoom; import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.matrix.json.event.MatrixJsonRoomMessageEvent; import io.kamax.matrix.json.event.MatrixJsonRoomMessageEvent;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.as.processor.command.CommandProcessor; import io.kamax.mxisd.as.processor.command.CommandProcessor;
import io.kamax.mxisd.as.processor.command.InviteCommandProcessor; import io.kamax.mxisd.as.processor.command.InviteCommandProcessor;
import io.kamax.mxisd.as.processor.command.LookupCommandProcessor;
import io.kamax.mxisd.as.processor.command.PingCommandProcessor; import io.kamax.mxisd.as.processor.command.PingCommandProcessor;
import org.apache.commons.cli.*;
import org.apache.commons.lang.text.StrBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -36,36 +40,48 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class MessageEventProcessor implements EventTypeProcessor { public class MessageEventProcessor implements EventTypeProcessor {
private static final Logger log = LoggerFactory.getLogger(MessageEventProcessor.class); private static final Logger log = LoggerFactory.getLogger(MessageEventProcessor.class);
private final Mxisd m;
private final MatrixApplicationServiceClient client; private final MatrixApplicationServiceClient client;
private Map<String, CommandProcessor> processors; private Map<String, CommandProcessor> processors;
public MessageEventProcessor(MatrixApplicationServiceClient client) { public MessageEventProcessor(Mxisd m, MatrixApplicationServiceClient client) {
this.m = m;
this.client = client; this.client = client;
processors = new HashMap<>(); processors = new HashMap<>();
processors.put("?", (m1, client1, room, cmdLine) -> room.sendNotice(getHelp()));
processors.put("help", (m1, client1, room, cmdLine) -> room.sendNotice(getHelp()));
processors.put(PingCommandProcessor.Command, new PingCommandProcessor()); processors.put(PingCommandProcessor.Command, new PingCommandProcessor());
processors.put(InviteCommandProcessor.Command, new InviteCommandProcessor()); processors.put(InviteCommandProcessor.Command, new InviteCommandProcessor());
processors.put(LookupCommandProcessor.Command, new LookupCommandProcessor());
} }
@Override @Override
public void process(JsonObject ev, _MatrixID sender, String roomId) { public void process(JsonObject ev, _MatrixID sender, String roomId) {
_MatrixRoom room = client.getRoom(roomId);
List<_MatrixID> joinedUsers = room.getJoinedUsers().stream().map(_MatrixUserProfile::getId).collect(Collectors.toList());
boolean joinedWithMainUser = joinedUsers.contains(client.getWhoAmI());
boolean isAdminPrivate = joinedWithMainUser && joinedUsers.size() == 2;
MatrixJsonRoomMessageEvent msgEv = new MatrixJsonRoomMessageEvent(ev); MatrixJsonRoomMessageEvent msgEv = new MatrixJsonRoomMessageEvent(ev);
if (StringUtils.equals("m.notice", msgEv.getBodyType())) { if (StringUtils.equals("m.notice", msgEv.getBodyType())) {
log.info("Ignoring automated message"); log.info("Ignoring automated message");
return; return;
} }
_MatrixRoom room = client.getRoom(roomId);
if (!m.getProfile().hasAnyRole(sender, m.getConfig().getAppsvc().getFeature().getAdmin().getAllowedRoles())) {
room.sendNotice("You are not allowed to interact with me.");
return;
}
List<_MatrixID> joinedUsers = room.getJoinedUsers().stream().map(_MatrixUserProfile::getId).collect(Collectors.toList());
boolean joinedWithMainUser = joinedUsers.contains(client.getWhoAmI());
boolean isAdminPrivate = joinedWithMainUser && joinedUsers.size() == 2;
if (!StringUtils.equals("m.text", msgEv.getBodyType())) { if (!StringUtils.equals("m.text", msgEv.getBodyType())) {
log.info("Unsupported message event type: {}", msgEv.getBodyType()); log.info("Unsupported message event type: {}", msgEv.getBodyType());
return; return;
@@ -73,20 +89,39 @@ public class MessageEventProcessor implements EventTypeProcessor {
String command = msgEv.getBody(); String command = msgEv.getBody();
if (!isAdminPrivate) { if (!isAdminPrivate) {
if (StringUtils.equals(command, "!mxisd")) { if (!StringUtils.startsWith(command, "!" + Mxisd.Name + " ")) {
// TODO show help
}
if (!StringUtils.startsWith(command, "!mxisd ")) {
// Not for us // Not for us
return; return;
} }
command = command.substring("!mxisd ".length()); command = command.substring(("!" + Mxisd.Name + " ").length());
} }
if (StringUtils.equals("ping", command)) { try {
room.sendText("Pong!"); CommandLineParser p = new DefaultParser();
CommandLine cmdLine = p.parse(new Options(), command.split(" ", 0));
String cmd = cmdLine.getArgList().get(0);
CommandProcessor cp = processors.get(cmd);
if (Objects.isNull(cp)) {
room.sendNotice("Unknown command: " + command + "\n\n" + getHelp());
} else {
cp.process(m, client, room, cmdLine);
}
} catch (ParseException e) {
room.sendNotice("Invalid input" + "\n\n" + getHelp());
} catch (RuntimeException e) {
room.sendNotice("Error when running command: " + e.getMessage());
} }
} }
public String getHelp() {
StrBuilder builder = new StrBuilder();
builder.appendln("Available commands:");
for (String cmd : processors.keySet()) {
builder.append("\t").appendln(cmd);
}
return builder.toString();
}
} }

View File

@@ -32,7 +32,7 @@ public class GenericSqlStoreSupplier implements IdentityStoreSupplier {
@Override @Override
public void accept(Mxisd mxisd) { public void accept(Mxisd mxisd) {
if (mxisd.getConfig().getSql().getAuth().isEnabled()) { if (mxisd.getConfig().getSql().getAuth().isEnabled()) {
AuthProviders.register(() -> new GenericSqlAuthProvider(mxisd.getConfig().getSql(), mxisd.getInvitationManager())); AuthProviders.register(() -> new GenericSqlAuthProvider(mxisd.getConfig().getSql(), mxisd.getInvite()));
} }
if (mxisd.getConfig().getSql().getDirectory().isEnabled()) { if (mxisd.getConfig().getSql().getDirectory().isEnabled()) {

View File

@@ -271,6 +271,19 @@ public class InvitationManager {
return lookupMgr.find(medium, address, cfg.getResolution().isRecursive()); return lookupMgr.find(medium, address, cfg.getResolution().isRecursive());
} }
public List<IThreePidInviteReply> listInvites() {
return new ArrayList<>(invitations.values());
}
public IThreePidInviteReply getInvite(String id) {
IThreePidInviteReply v = invitations.get(id);
if (Objects.isNull(v)) {
throw new ObjectNotFoundException("Invite", id);
}
return v;
}
public boolean canInvite(_MatrixID sender, JsonObject request) { public boolean canInvite(_MatrixID sender, JsonObject request) {
if (!request.has("medium")) { if (!request.has("medium")) {
log.info("Not a 3PID invite, allowing"); log.info("Not a 3PID invite, allowing");
@@ -417,6 +430,10 @@ public class InvitationManager {
log.debug("Invite expiration: finished"); log.debug("Invite expiration: finished");
} }
public void expireInvite(String id) {
publishMapping(getInvite(id), cfg.getExpiration().getResolveTo());
}
public void lookupMappingsForInvites() { public void lookupMappingsForInvites() {
if (!invitations.isEmpty()) { if (!invitations.isEmpty()) {
log.info("Checking for existing mapping for pending invites"); log.info("Checking for existing mapping for pending invites");

View File

@@ -37,10 +37,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -113,4 +110,8 @@ public class ProfileManager {
} }
} }
public boolean hasAnyRole(_MatrixID user, List<String> requiredRoles) {
return !requiredRoles.isEmpty() || Collections.disjoint(getRoles(user), requiredRoles);
}
} }