Add lookup and invite commands to the admin AS interface
This commit is contained in:
@@ -146,6 +146,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'
|
||||||
testCompile 'com.unboundid:unboundid-ldapsdk:4.0.9'
|
testCompile 'com.unboundid:unboundid-ldapsdk:4.0.9'
|
||||||
|
@@ -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)
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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)) {
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
room.sendText(response);
|
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";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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());
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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()) {
|
||||||
|
@@ -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");
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user