diff --git a/build.gradle b/build.gradle index 9d685b5..4ac3e55 100644 --- a/build.gradle +++ b/build.gradle @@ -145,6 +145,9 @@ dependencies { // HTTP server 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 'com.github.tomakehurst:wiremock:2.8.0' diff --git a/src/main/java/io/kamax/mxisd/HttpMxisd.java b/src/main/java/io/kamax/mxisd/HttpMxisd.java index 0df6252..0ee9d9b 100644 --- a/src/main/java/io/kamax/mxisd/HttpMxisd.java +++ b/src/main/java/io/kamax/mxisd/HttpMxisd.java @@ -72,7 +72,7 @@ public class HttpMxisd { HttpHandler asTxnHandler = SaneHandler.around(new AsTransactionHandler(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())); 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) .post(SessionValidateHandler.Path, sessValidateHandler) .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(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 .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()))) // 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 .get(AsUserHandler.Path, asUserHandler) diff --git a/src/main/java/io/kamax/mxisd/Mxisd.java b/src/main/java/io/kamax/mxisd/Mxisd.java index 4908eae..e6470ea 100644 --- a/src/main/java/io/kamax/mxisd/Mxisd.java +++ b/src/main/java/io/kamax/mxisd/Mxisd.java @@ -85,6 +85,9 @@ public class Mxisd { private NotificationManager notifMgr; private RegistrationManager regMgr; + // HS-specific classes + private Synapse synapse; + public Mxisd(MxisdConfig cfg) { this.cfg = cfg.build(); } @@ -104,7 +107,7 @@ public class Mxisd { signMgr = CryptoFactory.getSignatureManager(keyMgr); clientDns = new ClientDnsOverwrite(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); 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); dirMgr = new DirectoryManager(cfg.getDirectory(), clientDns, httpClient, DirectoryProviders.get()); regMgr = new RegistrationManager(cfg.getRegister(), httpClient, clientDns, invMgr); - asHander = new AppSvcManager(cfg, store, pMgr, notifMgr, synapse); + asHander = new AppSvcManager(this); } public MxisdConfig getConfig() { @@ -141,7 +144,7 @@ public class Mxisd { return keyMgr; } - public InvitationManager getInvitationManager() { + public InvitationManager getInvite() { return invMgr; } @@ -181,6 +184,14 @@ public class Mxisd { return notifMgr; } + public IStorage getStore() { + return store; + } + + public Synapse getSynapse() { + return synapse; + } + public void start() { build(); } diff --git a/src/main/java/io/kamax/mxisd/as/AppSvcManager.java b/src/main/java/io/kamax/mxisd/as/AppSvcManager.java index 5676c16..e389522 100644 --- a/src/main/java/io/kamax/mxisd/as/AppSvcManager.java +++ b/src/main/java/io/kamax/mxisd/as/AppSvcManager.java @@ -27,18 +27,16 @@ import io.kamax.matrix.client.MatrixClientContext; import io.kamax.matrix.client.as.MatrixApplicationServiceClient; import io.kamax.matrix.event.EventKey; 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.MembershipEventProcessor; import io.kamax.mxisd.as.processor.event.MessageEventProcessor; 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.MxisdConfig; import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.HttpMatrixException; 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.ormlite.dao.ASTransactionDao; import io.kamax.mxisd.util.GsonParser; @@ -72,9 +70,9 @@ public class AppSvcManager { private Map processors = new HashMap<>(); private Map> transactionsInProgress = new ConcurrentHashMap<>(); - public AppSvcManager(MxisdConfig mxisdCfg, IStorage store, ProfileManager profiler, NotificationManager notif, Synapse synapse) { - this.cfg = mxisdCfg.getAppsvc(); - this.store = store; + public AppSvcManager(Mxisd m) { + this.cfg = m.getConfig().getAppsvc(); + this.store = m.getStore(); /* 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(); - mxContext.setDomain(mxisdCfg.getMatrix().getDomain()); + mxContext.setDomain(m.getConfig().getMatrix().getDomain()); mxContext.setToken(cfg.getEndpoint().getToHS().getToken()); mxContext.setHsBaseUrl(cfg.getEndpoint().getToHS().getUrl()); client = new MatrixApplicationServiceClient(mxContext); - processors.put("m.room.member", new MembershipEventProcessor(client, mxisdCfg, profiler, notif, synapse)); - processors.put("m.room.message", new MessageEventProcessor(client)); + processors.put("m.room.member", new MembershipEventProcessor(client, m)); + processors.put("m.room.message", new MessageEventProcessor(m, client)); - processSynapseConfig(mxisdCfg); + processSynapseConfig(m.getConfig()); } private void processSynapseConfig(MxisdConfig cfg) { diff --git a/src/main/java/io/kamax/mxisd/as/processor/command/CommandProcessor.java b/src/main/java/io/kamax/mxisd/as/processor/command/CommandProcessor.java index 2c2b7c9..bb9f9f5 100644 --- a/src/main/java/io/kamax/mxisd/as/processor/command/CommandProcessor.java +++ b/src/main/java/io/kamax/mxisd/as/processor/command/CommandProcessor.java @@ -23,9 +23,10 @@ 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 org.apache.commons.cli.CommandLine; 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); } diff --git a/src/main/java/io/kamax/mxisd/as/processor/command/InviteCommandProcessor.java b/src/main/java/io/kamax/mxisd/as/processor/command/InviteCommandProcessor.java index a2a9fc1..adc32f0 100644 --- a/src/main/java/io/kamax/mxisd/as/processor/command/InviteCommandProcessor.java +++ b/src/main/java/io/kamax/mxisd/as/processor/command/InviteCommandProcessor.java @@ -23,31 +23,80 @@ 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.invitation.IThreePidInviteReply; +import org.apache.commons.cli.CommandLine; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.text.StrBuilder; + +import java.util.List; public class InviteCommandProcessor implements CommandProcessor { public static final String Command = "invite"; @Override - public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, String command, String[] arguments) { - if (arguments.length < 1) { - room.sendText(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); + public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, CommandLine cmdLine) { + if (cmdLine.getArgs().length < 2) { + room.sendNotice(buildHelp()); } 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 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) { @@ -61,8 +110,8 @@ public class InviteCommandProcessor implements CommandProcessor { private String buildHelp() { return "Available actions:\n\n" + "list - List invites\n" + - "show - Show detailed info about a specific invite\n" + - "revoke - Revoke a pending invite by resolving it to the configured Expiration user\n"; + "show ID - Show detailed info about a specific invite\n" + + "revoke ID - Revoke a pending invite by resolving it to the configured Expiration user\n"; } } diff --git a/src/main/java/io/kamax/mxisd/as/processor/command/LookupCommandProcessor.java b/src/main/java/io/kamax/mxisd/as/processor/command/LookupCommandProcessor.java new file mode 100644 index 0000000..ba5a5b0 --- /dev/null +++ b/src/main/java/io/kamax/mxisd/as/processor/command/LookupCommandProcessor.java @@ -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 . + */ + +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 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"; + } + +} diff --git a/src/main/java/io/kamax/mxisd/as/processor/command/PingCommandProcessor.java b/src/main/java/io/kamax/mxisd/as/processor/command/PingCommandProcessor.java index b8475f7..32f8364 100644 --- a/src/main/java/io/kamax/mxisd/as/processor/command/PingCommandProcessor.java +++ b/src/main/java/io/kamax/mxisd/as/processor/command/PingCommandProcessor.java @@ -23,14 +23,15 @@ 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 org.apache.commons.cli.CommandLine; public class PingCommandProcessor implements CommandProcessor { public static final String Command = "ping"; @Override - public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, String command, String[] arguments) { - room.sendText("Pong!"); + public void process(Mxisd m, _MatrixClient client, _MatrixRoom room, CommandLine cmdLine) { + room.sendNotice("Pong!"); } } diff --git a/src/main/java/io/kamax/mxisd/as/processor/event/MembershipEventProcessor.java b/src/main/java/io/kamax/mxisd/as/processor/event/MembershipEventProcessor.java index 05d4612..2f83fc9 100644 --- a/src/main/java/io/kamax/mxisd/as/processor/event/MembershipEventProcessor.java +++ b/src/main/java/io/kamax/mxisd/as/processor/event/MembershipEventProcessor.java @@ -28,6 +28,7 @@ import io.kamax.matrix._ThreePid; import io.kamax.matrix.client.as.MatrixApplicationServiceClient; import io.kamax.matrix.event.EventKey; import io.kamax.matrix.hs._MatrixRoom; +import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.backend.sql.synapse.Synapse; import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.invitation.IMatrixIdInvite; @@ -38,7 +39,6 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,16 +57,13 @@ public class MembershipEventProcessor implements EventTypeProcessor { public MembershipEventProcessor( MatrixApplicationServiceClient client, - MxisdConfig cfg, - ProfileManager profiler, - NotificationManager notif, - Synapse synapse + Mxisd m ) { this.client = client; - this.cfg = cfg; - this.profiler = profiler; - this.notif = notif; - this.synapse = synapse; + this.cfg = m.getConfig(); + this.profiler = m.getProfile(); + this.notif = m.getNotif(); + this.synapse = m.getSynapse(); } @Override @@ -121,8 +118,8 @@ public class MembershipEventProcessor implements EventTypeProcessor { } private void processForMainUser(String roomId, _MatrixID sender) { - List roles = profiler.getRoles(sender); - if (Collections.disjoint(roles, cfg.getAppsvc().getFeature().getAdmin().getAllowedRoles())) { + boolean isAllowed = profiler.hasAnyRole(sender, cfg.getAppsvc().getFeature().getAdmin().getAllowedRoles()); + if (!isAllowed) { log.info("Sender does not have any of the required roles, denying"); client.getRoom(roomId).tryLeave().ifPresent(err -> { log.warn("Could not decline invite to room {}: {} - {}", roomId, err.getErrcode(), err.getError()); diff --git a/src/main/java/io/kamax/mxisd/as/processor/event/MessageEventProcessor.java b/src/main/java/io/kamax/mxisd/as/processor/event/MessageEventProcessor.java index 2f50490..06850dc 100644 --- a/src/main/java/io/kamax/mxisd/as/processor/event/MessageEventProcessor.java +++ b/src/main/java/io/kamax/mxisd/as/processor/event/MessageEventProcessor.java @@ -26,9 +26,13 @@ import io.kamax.matrix._MatrixUserProfile; import io.kamax.matrix.client.as.MatrixApplicationServiceClient; import io.kamax.matrix.hs._MatrixRoom; 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.InviteCommandProcessor; +import io.kamax.mxisd.as.processor.command.LookupCommandProcessor; 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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,36 +40,48 @@ import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; public class MessageEventProcessor implements EventTypeProcessor { private static final Logger log = LoggerFactory.getLogger(MessageEventProcessor.class); + private final Mxisd m; private final MatrixApplicationServiceClient client; private Map processors; - public MessageEventProcessor(MatrixApplicationServiceClient client) { + public MessageEventProcessor(Mxisd m, MatrixApplicationServiceClient client) { + this.m = m; this.client = client; 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(InviteCommandProcessor.Command, new InviteCommandProcessor()); + processors.put(LookupCommandProcessor.Command, new LookupCommandProcessor()); } @Override 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); if (StringUtils.equals("m.notice", msgEv.getBodyType())) { log.info("Ignoring automated message"); 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())) { log.info("Unsupported message event type: {}", msgEv.getBodyType()); return; @@ -73,20 +89,39 @@ public class MessageEventProcessor implements EventTypeProcessor { String command = msgEv.getBody(); if (!isAdminPrivate) { - if (StringUtils.equals(command, "!mxisd")) { - // TODO show help - } - if (!StringUtils.startsWith(command, "!mxisd ")) { + if (!StringUtils.startsWith(command, "!" + Mxisd.Name + " ")) { // Not for us return; } - command = command.substring("!mxisd ".length()); + command = command.substring(("!" + Mxisd.Name + " ").length()); } - if (StringUtils.equals("ping", command)) { - room.sendText("Pong!"); + try { + 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(); + } + } diff --git a/src/main/java/io/kamax/mxisd/backend/sql/generic/GenericSqlStoreSupplier.java b/src/main/java/io/kamax/mxisd/backend/sql/generic/GenericSqlStoreSupplier.java index 4983369..21eb465 100644 --- a/src/main/java/io/kamax/mxisd/backend/sql/generic/GenericSqlStoreSupplier.java +++ b/src/main/java/io/kamax/mxisd/backend/sql/generic/GenericSqlStoreSupplier.java @@ -32,7 +32,7 @@ public class GenericSqlStoreSupplier implements IdentityStoreSupplier { @Override public void accept(Mxisd mxisd) { 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()) { diff --git a/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java b/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java index 8dfcc2a..11e665b 100644 --- a/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java +++ b/src/main/java/io/kamax/mxisd/invitation/InvitationManager.java @@ -271,6 +271,19 @@ public class InvitationManager { return lookupMgr.find(medium, address, cfg.getResolution().isRecursive()); } + public List 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) { if (!request.has("medium")) { log.info("Not a 3PID invite, allowing"); @@ -417,6 +430,10 @@ public class InvitationManager { log.debug("Invite expiration: finished"); } + public void expireInvite(String id) { + publishMapping(getInvite(id), cfg.getExpiration().getResolveTo()); + } + public void lookupMappingsForInvites() { if (!invitations.isEmpty()) { log.info("Checking for existing mapping for pending invites"); diff --git a/src/main/java/io/kamax/mxisd/profile/ProfileManager.java b/src/main/java/io/kamax/mxisd/profile/ProfileManager.java index c803626..f8c143a 100644 --- a/src/main/java/io/kamax/mxisd/profile/ProfileManager.java +++ b/src/main/java/io/kamax/mxisd/profile/ProfileManager.java @@ -37,10 +37,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -113,4 +110,8 @@ public class ProfileManager { } } + public boolean hasAnyRole(_MatrixID user, List requiredRoles) { + return !requiredRoles.isEmpty() || Collections.disjoint(getRoles(user), requiredRoles); + } + }