Further work
This commit is contained in:
35
src/main/groovy/io/kamax/mxisd/config/SessionConfig.java
Normal file
35
src/main/groovy/io/kamax/mxisd/config/SessionConfig.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.config;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("session")
|
||||||
|
public class SessionConfig {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(SessionConfig.class);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* mxisd - Matrix Identity Server Daemon
|
|
||||||
* Copyright (C) 2017 Maxime Dor
|
|
||||||
*
|
|
||||||
* https://max.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.config.invite.medium;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties("invite.medium.email")
|
|
||||||
public class EmailInviteConfig {
|
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(EmailInviteConfig.class);
|
|
||||||
|
|
||||||
private String template;
|
|
||||||
|
|
||||||
public String getTemplate() {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTemplate(String template) {
|
|
||||||
this.template = template;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void build() {
|
|
||||||
log.info("--- E-mail invites config ---");
|
|
||||||
|
|
||||||
if (!StringUtils.startsWith(getTemplate(), "classpath:")) {
|
|
||||||
if (StringUtils.isBlank(getTemplate())) {
|
|
||||||
log.warn("invite.medium.email is empty! Will not send invites");
|
|
||||||
} else {
|
|
||||||
File cp = new File(getTemplate()).getAbsoluteFile();
|
|
||||||
log.info("Template: {}", cp.getAbsolutePath());
|
|
||||||
if (!cp.exists() || !cp.isFile() || !cp.canRead()) {
|
|
||||||
log.warn(getTemplate() + " does not exist, is not a file or cannot be read");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.info("Template: Built-in: {}", getTemplate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -29,7 +29,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConfigurationProperties(prefix = "threepid.email.connector.provider.smtp")
|
@ConfigurationProperties(prefix = "threepid.medium.email.connectors.smtp")
|
||||||
public class EmailSmtpConfig {
|
public class EmailSmtpConfig {
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(EmailSmtpConfig.class);
|
private Logger log = LoggerFactory.getLogger(EmailSmtpConfig.class);
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
package io.kamax.mxisd.config.threepid.medium;
|
package io.kamax.mxisd.config.threepid.medium;
|
||||||
|
|
||||||
import io.kamax.mxisd.config.MatrixConfig;
|
import io.kamax.mxisd.config.MatrixConfig;
|
||||||
|
import io.kamax.mxisd.exception.ConfigurationException;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.lang.WordUtils;
|
import org.apache.commons.lang.WordUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -35,43 +36,81 @@ import javax.annotation.PostConstruct;
|
|||||||
@ConfigurationProperties("threepid.medium.email")
|
@ConfigurationProperties("threepid.medium.email")
|
||||||
public class EmailConfig {
|
public class EmailConfig {
|
||||||
|
|
||||||
|
public static class Identity {
|
||||||
|
private String from;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrom(String from) {
|
||||||
|
this.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generator;
|
||||||
|
private String connector;
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(EmailConfig.class);
|
private Logger log = LoggerFactory.getLogger(EmailConfig.class);
|
||||||
|
|
||||||
private MatrixConfig mxCfg;
|
private MatrixConfig mxCfg;
|
||||||
|
private Identity identity = new Identity();
|
||||||
private String from;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public EmailConfig(MatrixConfig mxCfg) {
|
public EmailConfig(MatrixConfig mxCfg) {
|
||||||
this.mxCfg = mxCfg;
|
this.mxCfg = mxCfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFrom() {
|
public Identity getIdentity() {
|
||||||
return from;
|
return identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrom(String from) {
|
public String getGenerator() {
|
||||||
this.from = from;
|
return generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public void setGenerator(String generator) {
|
||||||
return name;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public String getConnector() {
|
||||||
this.name = name;
|
return connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnector(String connector) {
|
||||||
|
this.connector = connector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void build() {
|
public void build() {
|
||||||
log.info("--- E-mail config ---");
|
log.info("--- E-mail config ---");
|
||||||
log.info("From: {}", getFrom());
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(getName())) {
|
if (StringUtils.isBlank(getGenerator())) {
|
||||||
setName(WordUtils.capitalize(mxCfg.getDomain()) + " Identity Server");
|
throw new ConfigurationException("generator");
|
||||||
}
|
}
|
||||||
log.info("Name: {}", getName());
|
|
||||||
|
if (StringUtils.isBlank(getConnector())) {
|
||||||
|
throw new ConfigurationException("connector");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("From: {}", identity.getFrom());
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(identity.getName())) {
|
||||||
|
identity.setName(WordUtils.capitalize(mxCfg.getDomain()) + " Identity Server");
|
||||||
|
}
|
||||||
|
log.info("Name: {}", identity.getName());
|
||||||
|
log.info("Generator: {}", getGenerator());
|
||||||
|
log.info("Connector: {}", getConnector());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.config.threepid.medium;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("threepid.medium.email.generators.template")
|
||||||
|
public class EmailTemplateConfig {
|
||||||
|
|
||||||
|
private static Logger log = LoggerFactory.getLogger(EmailTemplateConfig.class);
|
||||||
|
private static final String classpathPrefix = "classpath:";
|
||||||
|
|
||||||
|
private static String getName(String path) {
|
||||||
|
if (StringUtils.startsWith(path, classpathPrefix)) {
|
||||||
|
return "Built-in (" + path.substring(classpathPrefix.length()) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Session {
|
||||||
|
|
||||||
|
private String validation;
|
||||||
|
|
||||||
|
public String getValidation() {
|
||||||
|
return validation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidation(String validation) {
|
||||||
|
this.validation = validation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String invite;
|
||||||
|
private Session session = new Session();
|
||||||
|
|
||||||
|
public String getInvite() {
|
||||||
|
return invite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInvite(String invite) {
|
||||||
|
this.invite = invite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Session getSession() {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void build() {
|
||||||
|
log.info("--- E-mail Generator templates config ---");
|
||||||
|
log.info("Invite: {}", getName(getInvite()));
|
||||||
|
log.info("Session validation: {}", getName(getSession().getValidation()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -29,7 +29,7 @@ import io.kamax.mxisd.controller.v1.io.SessionPhoneTokenRequestJson
|
|||||||
import io.kamax.mxisd.exception.BadRequestException
|
import io.kamax.mxisd.exception.BadRequestException
|
||||||
import io.kamax.mxisd.invitation.InvitationManager
|
import io.kamax.mxisd.invitation.InvitationManager
|
||||||
import io.kamax.mxisd.lookup.ThreePidValidation
|
import io.kamax.mxisd.lookup.ThreePidValidation
|
||||||
import io.kamax.mxisd.mapping.MappingManager
|
import io.kamax.mxisd.session.SessionMananger
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.apache.http.HttpStatus
|
import org.apache.http.HttpStatus
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
@@ -48,7 +48,7 @@ import java.nio.charset.StandardCharsets
|
|||||||
class SessionController {
|
class SessionController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MappingManager mgr
|
private SessionMananger mgr
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private InvitationManager invMgr;
|
private InvitationManager invMgr;
|
||||||
|
@@ -24,5 +24,10 @@ import org.springframework.http.HttpStatus
|
|||||||
import org.springframework.web.bind.annotation.ResponseStatus
|
import org.springframework.web.bind.annotation.ResponseStatus
|
||||||
|
|
||||||
@ResponseStatus(value = HttpStatus.NOT_IMPLEMENTED)
|
@ResponseStatus(value = HttpStatus.NOT_IMPLEMENTED)
|
||||||
class NotImplementedException extends RuntimeException {
|
public class NotImplementedException extends RuntimeException {
|
||||||
|
|
||||||
|
public NotImplementedException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -26,14 +26,13 @@ import io.kamax.mxisd.config.DnsOverwrite;
|
|||||||
import io.kamax.mxisd.config.DnsOverwriteEntry;
|
import io.kamax.mxisd.config.DnsOverwriteEntry;
|
||||||
import io.kamax.mxisd.exception.BadRequestException;
|
import io.kamax.mxisd.exception.BadRequestException;
|
||||||
import io.kamax.mxisd.exception.MappingAlreadyExistsException;
|
import io.kamax.mxisd.exception.MappingAlreadyExistsException;
|
||||||
import io.kamax.mxisd.invitation.generator.IInviteContentGenerator;
|
|
||||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||||
import io.kamax.mxisd.lookup.ThreePidMapping;
|
import io.kamax.mxisd.lookup.ThreePidMapping;
|
||||||
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
||||||
|
import io.kamax.mxisd.notification.NotificationManager;
|
||||||
import io.kamax.mxisd.signature.SignatureManager;
|
import io.kamax.mxisd.signature.SignatureManager;
|
||||||
import io.kamax.mxisd.storage.IStorage;
|
import io.kamax.mxisd.storage.IStorage;
|
||||||
import io.kamax.mxisd.storage.ormlite.ThreePidInviteIO;
|
import io.kamax.mxisd.storage.ormlite.ThreePidInviteIO;
|
||||||
import io.kamax.mxisd.threepid.connector.IThreePidConnector;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang.RandomStringUtils;
|
import org.apache.commons.lang.RandomStringUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@@ -84,35 +83,15 @@ public class InvitationManager {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DnsOverwrite dns;
|
private DnsOverwrite dns;
|
||||||
|
|
||||||
private Map<String, IInviteContentGenerator> generators;
|
private NotificationManager notifMgr;
|
||||||
private Map<String, IThreePidConnector> connectors;
|
|
||||||
|
|
||||||
private CloseableHttpClient client;
|
private CloseableHttpClient client;
|
||||||
private Gson gson;
|
private Gson gson;
|
||||||
private Timer refreshTimer;
|
private Timer refreshTimer;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public InvitationManager(
|
public InvitationManager(NotificationManager notifMgr) {
|
||||||
List<IInviteContentGenerator> generatorList,
|
this.notifMgr = notifMgr;
|
||||||
List<IThreePidConnector> connectorList
|
|
||||||
) {
|
|
||||||
generators = new HashMap<>();
|
|
||||||
generatorList.forEach(sender -> { // FIXME to support several possible implementations
|
|
||||||
if (generators.containsKey(sender.getMedium())) {
|
|
||||||
throw new RuntimeException("More than one " + sender.getMedium() + " content generator");
|
|
||||||
}
|
|
||||||
|
|
||||||
generators.put(sender.getMedium(), sender);
|
|
||||||
});
|
|
||||||
|
|
||||||
connectors = new HashMap<>();
|
|
||||||
connectorList.forEach(connector -> { // FIXME to support several possible implementations
|
|
||||||
if (connectors.containsKey(connector.getMedium())) {
|
|
||||||
throw new RuntimeException("More than one " + connector.getMedium() + " connector");
|
|
||||||
}
|
|
||||||
|
|
||||||
connectors.put(connector.getMedium(), connector);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
@@ -221,9 +200,7 @@ public class InvitationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized IThreePidInviteReply storeInvite(IThreePidInvite invitation) { // TODO better sync
|
public synchronized IThreePidInviteReply storeInvite(IThreePidInvite invitation) { // TODO better sync
|
||||||
IInviteContentGenerator generator = generators.get(invitation.getMedium());
|
if (!notifMgr.isMediumSupported(invitation.getMedium())) {
|
||||||
IThreePidConnector connector = connectors.get(invitation.getMedium());
|
|
||||||
if (generator == null || connector == null) {
|
|
||||||
throw new BadRequestException("Medium type " + invitation.getMedium() + " is not supported");
|
throw new BadRequestException("Medium type " + invitation.getMedium() + " is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +223,7 @@ public class InvitationManager {
|
|||||||
IThreePidInviteReply reply = new ThreePidInviteReply(invId, invitation, token, displayName);
|
IThreePidInviteReply reply = new ThreePidInviteReply(invId, invitation, token, displayName);
|
||||||
|
|
||||||
log.info("Performing invite to {}:{}", invitation.getMedium(), invitation.getAddress());
|
log.info("Performing invite to {}:{}", invitation.getMedium(), invitation.getAddress());
|
||||||
connector.send(reply, generator.generate(reply));
|
notifMgr.send(reply);
|
||||||
|
|
||||||
log.info("Storing invite under ID {}", invId);
|
log.info("Storing invite under ID {}", invId);
|
||||||
storage.insertInvite(reply);
|
storage.insertInvite(reply);
|
||||||
|
@@ -18,14 +18,17 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.invitation.generator;
|
package io.kamax.mxisd.notification;
|
||||||
|
|
||||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||||
|
import io.kamax.mxisd.threepid.session.IThreePidSession;
|
||||||
|
|
||||||
public interface IInviteContentGenerator {
|
public interface INotificationHandler {
|
||||||
|
|
||||||
String getMedium();
|
String getMedium();
|
||||||
|
|
||||||
String generate(IThreePidInviteReply invite);
|
void notify(IThreePidInviteReply invite);
|
||||||
|
|
||||||
|
void notify(IThreePidSession session);
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.notification;
|
||||||
|
|
||||||
|
import io.kamax.mxisd.exception.NotImplementedException;
|
||||||
|
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||||
|
import io.kamax.mxisd.threepid.session.IThreePidSession;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class NotificationManager {
|
||||||
|
|
||||||
|
private Map<String, INotificationHandler> handlers;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public NotificationManager(List<INotificationHandler> handlers) {
|
||||||
|
this.handlers = new HashMap<>();
|
||||||
|
handlers.forEach(h -> this.handlers.put(h.getMedium(), h));
|
||||||
|
}
|
||||||
|
|
||||||
|
private INotificationHandler ensureMedium(String medium) {
|
||||||
|
INotificationHandler handler = handlers.get(medium);
|
||||||
|
if (handler == null) {
|
||||||
|
throw new NotImplementedException(medium + " is not a supported 3PID medium type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMediumSupported(String medium) {
|
||||||
|
return handlers.containsKey(medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendForInvite(IThreePidInviteReply invite) {
|
||||||
|
ensureMedium(invite.getInvite().getMedium()).notify(invite);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendForValidation(IThreePidSession session) {
|
||||||
|
ensureMedium(session.getThreePid().getMedium()).notify(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendforRemotePublish(IThreePidSession session) {
|
||||||
|
throw new NotImplementedException("Remote publish of 3PID bind");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -18,14 +18,16 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.mapping;
|
package io.kamax.mxisd.session;
|
||||||
|
|
||||||
import io.kamax.matrix.ThreePidMedium;
|
import io.kamax.matrix.ThreePidMedium;
|
||||||
import io.kamax.mxisd.ThreePid;
|
import io.kamax.mxisd.ThreePid;
|
||||||
|
import io.kamax.mxisd.config.SessionConfig;
|
||||||
import io.kamax.mxisd.exception.InvalidCredentialsException;
|
import io.kamax.mxisd.exception.InvalidCredentialsException;
|
||||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||||
import io.kamax.mxisd.lookup.ThreePidValidation;
|
import io.kamax.mxisd.lookup.ThreePidValidation;
|
||||||
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
||||||
|
import io.kamax.mxisd.notification.NotificationManager;
|
||||||
import io.kamax.mxisd.storage.IStorage;
|
import io.kamax.mxisd.storage.IStorage;
|
||||||
import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
|
import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
|
||||||
import io.kamax.mxisd.threepid.session.ThreePidSession;
|
import io.kamax.mxisd.threepid.session.ThreePidSession;
|
||||||
@@ -40,16 +42,21 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class MappingManager {
|
public class SessionMananger {
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(MappingManager.class);
|
private Logger log = LoggerFactory.getLogger(SessionMananger.class);
|
||||||
|
|
||||||
|
private SessionConfig cfg;
|
||||||
private IStorage storage;
|
private IStorage storage;
|
||||||
private LookupStrategy lookup;
|
private LookupStrategy lookup;
|
||||||
|
private NotificationManager notifMgr;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public MappingManager(IStorage storage, LookupStrategy lookup) {
|
public SessionMananger(SessionConfig cfg, IStorage storage, LookupStrategy lookup, NotificationManager notifMgr) {
|
||||||
|
this.cfg = cfg;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
this.lookup = lookup;
|
||||||
|
this.notifMgr = notifMgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThreePidSession getSession(String sid, String secret) {
|
private ThreePidSession getSession(String sid, String secret) {
|
||||||
@@ -78,7 +85,8 @@ public class MappingManager {
|
|||||||
log.info("We already have a session for {}: {}", tpid, session.getId());
|
log.info("We already have a session for {}: {}", tpid, session.getId());
|
||||||
if (session.getAttempt() < attempt) {
|
if (session.getAttempt() < attempt) {
|
||||||
log.info("Received attempt {} is greater than stored attempt {}, sending validation communication", attempt, session.getAttempt());
|
log.info("Received attempt {} is greater than stored attempt {}, sending validation communication", attempt, session.getAttempt());
|
||||||
// TODO send via connector
|
notifMgr.sendForValidation(session);
|
||||||
|
log.info("Sent validation notification to {}", tpid);
|
||||||
session.increaseAttempt();
|
session.increaseAttempt();
|
||||||
storage.updateThreePidSession(session.getDao());
|
storage.updateThreePidSession(session.getDao());
|
||||||
}
|
}
|
||||||
@@ -95,8 +103,8 @@ public class MappingManager {
|
|||||||
ThreePidSession session = new ThreePidSession(sessionId, server, tpid, secret, attempt, nextLink, token);
|
ThreePidSession session = new ThreePidSession(sessionId, server, tpid, secret, attempt, nextLink, token);
|
||||||
log.info("Generated new session {} to validate {} from server {}", sessionId, tpid, server);
|
log.info("Generated new session {} to validate {} from server {}", sessionId, tpid, server);
|
||||||
|
|
||||||
// TODO send via connector
|
notifMgr.sendForValidation(session);
|
||||||
// log.info("Sent validation notification to {}", tpid);
|
log.info("Sent validation notification to {}", tpid);
|
||||||
|
|
||||||
storage.insertThreePidSession(session.getDao());
|
storage.insertThreePidSession(session.getDao());
|
||||||
log.info("Stored session {}", sessionId, tpid, server);
|
log.info("Stored session {}", sessionId, tpid, server);
|
||||||
@@ -124,13 +132,7 @@ public class MappingManager {
|
|||||||
ThreePidSession session = getSessionIfValidated(sid, secret);
|
ThreePidSession session = getSessionIfValidated(sid, secret);
|
||||||
log.info("Attempting bind of {} on session {} from server {}", mxid, session.getId(), session.getServer());
|
log.info("Attempting bind of {} on session {} from server {}", mxid, session.getId(), session.getServer());
|
||||||
|
|
||||||
// We lookup if the 3PID is already known locally.
|
// We lookup if the 3PID is already known remotely.
|
||||||
// If it is, we do not need to process any further as it is already bound.
|
|
||||||
Optional<SingleLookupReply> rLocal = lookup.findLocal(session.getThreePid().getMedium(), session.getThreePid().getAddress());
|
|
||||||
boolean knownLocal = rLocal.isPresent() && StringUtils.equals(rLocal.get().getMxid().getId(), mxid);
|
|
||||||
log.info("Mapping {} -> {} is " + (knownLocal ? "already" : "not") + " known locally", mxid, session.getThreePid());
|
|
||||||
|
|
||||||
// MXID is not known locally, checking remotely
|
|
||||||
Optional<SingleLookupReply> rRemote = lookup.findRemote(session.getThreePid().getMedium(), session.getThreePid().getAddress());
|
Optional<SingleLookupReply> rRemote = lookup.findRemote(session.getThreePid().getMedium(), session.getThreePid().getAddress());
|
||||||
boolean knownRemote = rRemote.isPresent() && StringUtils.equals(rRemote.get().getMxid().getId(), mxid);
|
boolean knownRemote = rRemote.isPresent() && StringUtils.equals(rRemote.get().getMxid().getId(), mxid);
|
||||||
log.info("Mapping {} -> {} is " + (knownRemote ? "already" : "not") + " known remotely", mxid, session.getThreePid());
|
log.info("Mapping {} -> {} is " + (knownRemote ? "already" : "not") + " known remotely", mxid, session.getThreePid());
|
||||||
@@ -143,25 +145,28 @@ public class MappingManager {
|
|||||||
isLocalDomain = session.getThreePid().getAddress().isEmpty(); // FIXME only for testing
|
isLocalDomain = session.getThreePid().getAddress().isEmpty(); // FIXME only for testing
|
||||||
}
|
}
|
||||||
if (knownRemote) {
|
if (knownRemote) {
|
||||||
if (isLocalDomain && !knownLocal) {
|
|
||||||
log.warn("Mapping {} -> {} is not known locally but is about a local domain!");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("No further action needed for Mapping {} -> {}");
|
log.info("No further action needed for Mapping {} -> {}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We lookup if the 3PID is already known locally.
|
||||||
|
Optional<SingleLookupReply> rLocal = lookup.findLocal(session.getThreePid().getMedium(), session.getThreePid().getAddress());
|
||||||
|
boolean knownLocal = rLocal.isPresent() && StringUtils.equals(rLocal.get().getMxid().getId(), mxid);
|
||||||
|
log.info("Mapping {} -> {} is " + (knownLocal ? "already" : "not") + " known locally", mxid, session.getThreePid());
|
||||||
|
|
||||||
// This might need a configuration by medium type?
|
// This might need a configuration by medium type?
|
||||||
if (knownLocal) { // 3PID is ony known local
|
if (knownLocal) { // 3PID is ony known local
|
||||||
if (isLocalDomain) {
|
if (isLocalDomain) {
|
||||||
// TODO
|
// TODO
|
||||||
// 1. Check if global publishing is enabled, allowed and offered. If one is no, return.
|
// 1. Check if global publishing is enabled, allowed and offered. If one is no, return.
|
||||||
// 2. Publish globally
|
// 2. Publish globally
|
||||||
|
notifMgr.sendforRemotePublish(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (System.currentTimeMillis() % 2 == 0) {
|
if (System.currentTimeMillis() % 2 == 0) { // FIXME only for testing
|
||||||
// TODO
|
// TODO
|
||||||
// 1. Check if configured to publish globally non-local domain. If no, return
|
// 1. Check if configured to publish globally non-local domain. If no, return
|
||||||
|
notifMgr.sendforRemotePublish(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@@ -172,6 +177,7 @@ public class MappingManager {
|
|||||||
// 2. call mxisd-specific endpoint to publish globally
|
// 2. call mxisd-specific endpoint to publish globally
|
||||||
// 3. check regularly on client page for a binding
|
// 3. check regularly on client page for a binding
|
||||||
// 4. when found, show page "Done globally!"
|
// 4. when found, show page "Done globally!"
|
||||||
|
notifMgr.sendforRemotePublish(session);
|
||||||
} else {
|
} else {
|
||||||
if (isLocalDomain) { // 3PID is not known anywhere but is a local domain
|
if (isLocalDomain) { // 3PID is not known anywhere but is a local domain
|
||||||
// TODO
|
// TODO
|
||||||
@@ -180,6 +186,7 @@ public class MappingManager {
|
|||||||
} else { // 3PID is not known anywhere and is remote
|
} else { // 3PID is not known anywhere and is remote
|
||||||
// TODO
|
// TODO
|
||||||
// Proxy to configurable IS, by default Matrix.org
|
// Proxy to configurable IS, by default Matrix.org
|
||||||
|
notifMgr.sendforRemotePublish(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -20,12 +20,10 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.threepid.connector;
|
package io.kamax.mxisd.threepid.connector;
|
||||||
|
|
||||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
|
||||||
|
|
||||||
public interface IThreePidConnector {
|
public interface IThreePidConnector {
|
||||||
|
|
||||||
|
String getId();
|
||||||
|
|
||||||
String getMedium();
|
String getMedium();
|
||||||
|
|
||||||
void send(IThreePidInviteReply invite, String content);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -18,14 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.threepid.connector;
|
package io.kamax.mxisd.threepid.connector.email;
|
||||||
|
|
||||||
import com.sun.mail.smtp.SMTPTransport;
|
import com.sun.mail.smtp.SMTPTransport;
|
||||||
import io.kamax.matrix.ThreePidMedium;
|
import io.kamax.matrix.ThreePidMedium;
|
||||||
import io.kamax.mxisd.config.threepid.connector.EmailSmtpConfig;
|
import io.kamax.mxisd.config.threepid.connector.EmailSmtpConfig;
|
||||||
import io.kamax.mxisd.config.threepid.medium.EmailConfig;
|
|
||||||
import io.kamax.mxisd.exception.ConfigurationException;
|
|
||||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -42,26 +39,22 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class EmailSmtpConnector implements IThreePidConnector {
|
public class EmailSmtpConnector implements IEmailConnector {
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(EmailSmtpConnector.class);
|
private Logger log = LoggerFactory.getLogger(EmailSmtpConnector.class);
|
||||||
|
|
||||||
private EmailSmtpConfig cfg;
|
private EmailSmtpConfig cfg;
|
||||||
|
|
||||||
private Session session;
|
private Session session;
|
||||||
private InternetAddress sender;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public EmailSmtpConnector(EmailConfig cfg, EmailSmtpConfig smtpCfg) {
|
public EmailSmtpConnector(EmailSmtpConfig cfg) {
|
||||||
try {
|
this.cfg = cfg;
|
||||||
session = Session.getInstance(System.getProperties());
|
session = Session.getInstance(System.getProperties());
|
||||||
sender = new InternetAddress(cfg.getFrom(), cfg.getName());
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// What are we supposed to do with this?!
|
|
||||||
throw new ConfigurationException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cfg = smtpCfg;
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "smtp";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,20 +63,17 @@ public class EmailSmtpConnector implements IThreePidConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(IThreePidInviteReply invite, String content) {
|
public void send(String senderAddress, String senderName, String recipient, String content) {
|
||||||
if (!ThreePidMedium.Email.is(invite.getInvite().getMedium())) {
|
|
||||||
throw new IllegalArgumentException(invite.getInvite().getMedium() + " is not a supported 3PID type");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
InternetAddress sender = new InternetAddress(senderAddress, senderName);
|
||||||
MimeMessage msg = new MimeMessage(session, IOUtils.toInputStream(content, StandardCharsets.UTF_8));
|
MimeMessage msg = new MimeMessage(session, IOUtils.toInputStream(content, StandardCharsets.UTF_8));
|
||||||
msg.setHeader("X-Mailer", "mxisd"); // TODO set version
|
msg.setHeader("X-Mailer", "mxisd"); // FIXME set version
|
||||||
msg.setSentDate(new Date());
|
msg.setSentDate(new Date());
|
||||||
msg.setFrom(sender);
|
msg.setFrom(sender);
|
||||||
msg.setRecipients(Message.RecipientType.TO, invite.getInvite().getAddress());
|
msg.setRecipients(Message.RecipientType.TO, recipient);
|
||||||
msg.saveChanges();
|
msg.saveChanges();
|
||||||
|
|
||||||
log.info("Sending invite to {} via SMTP using {}:{}", invite.getInvite().getAddress(), cfg.getHost(), cfg.getPort());
|
log.info("Sending invite to {} via SMTP using {}:{}", recipient, cfg.getHost(), cfg.getPort());
|
||||||
SMTPTransport transport = (SMTPTransport) session.getTransport("smtp");
|
SMTPTransport transport = (SMTPTransport) session.getTransport("smtp");
|
||||||
transport.setStartTLS(cfg.getTls() > 0);
|
transport.setStartTLS(cfg.getTls() > 0);
|
||||||
transport.setRequireStartTLS(cfg.getTls() > 1);
|
transport.setRequireStartTLS(cfg.getTls() > 1);
|
||||||
@@ -91,13 +81,13 @@ public class EmailSmtpConnector implements IThreePidConnector {
|
|||||||
log.info("Connecting to {}:{}", cfg.getHost(), cfg.getPort());
|
log.info("Connecting to {}:{}", cfg.getHost(), cfg.getPort());
|
||||||
transport.connect(cfg.getHost(), cfg.getPort(), cfg.getLogin(), cfg.getPassword());
|
transport.connect(cfg.getHost(), cfg.getPort(), cfg.getLogin(), cfg.getPassword());
|
||||||
try {
|
try {
|
||||||
transport.sendMessage(msg, InternetAddress.parse(invite.getInvite().getAddress()));
|
transport.sendMessage(msg, InternetAddress.parse(recipient));
|
||||||
log.info("Invite to {} was sent", invite.getInvite().getAddress());
|
log.info("Invite to {} was sent", recipient);
|
||||||
} finally {
|
} finally {
|
||||||
transport.close();
|
transport.close();
|
||||||
}
|
}
|
||||||
} catch (MessagingException e) {
|
} catch (UnsupportedEncodingException | MessagingException e) {
|
||||||
throw new RuntimeException("Unable to send e-mail invite to " + invite.getInvite().getAddress(), e);
|
throw new RuntimeException("Unable to send e-mail invite to " + recipient, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.threepid.connector.email;
|
||||||
|
|
||||||
|
import io.kamax.matrix.ThreePidMedium;
|
||||||
|
import io.kamax.mxisd.threepid.connector.IThreePidConnector;
|
||||||
|
|
||||||
|
public interface IEmailConnector extends IThreePidConnector {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String getMedium() {
|
||||||
|
return ThreePidMedium.Email.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(String senderAddress, String senderName, String recipient, String content);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.threepid.notification;
|
||||||
|
|
||||||
|
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||||
|
import io.kamax.mxisd.threepid.session.IThreePidSession;
|
||||||
|
|
||||||
|
public interface INotificationGenerator {
|
||||||
|
|
||||||
|
String getId();
|
||||||
|
|
||||||
|
String getMedium();
|
||||||
|
|
||||||
|
String get(IThreePidInviteReply invite);
|
||||||
|
|
||||||
|
String getForValidation(IThreePidSession session);
|
||||||
|
|
||||||
|
String getForRemotePublishingValidation(IThreePidSession session);
|
||||||
|
|
||||||
|
}
|
@@ -18,13 +18,14 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.invitation.generator;
|
package io.kamax.mxisd.threepid.notification.email;
|
||||||
|
|
||||||
import io.kamax.matrix.ThreePidMedium;
|
import io.kamax.mxisd.ThreePid;
|
||||||
import io.kamax.mxisd.config.MatrixConfig;
|
import io.kamax.mxisd.config.MatrixConfig;
|
||||||
import io.kamax.mxisd.config.invite.medium.EmailInviteConfig;
|
|
||||||
import io.kamax.mxisd.config.threepid.medium.EmailConfig;
|
import io.kamax.mxisd.config.threepid.medium.EmailConfig;
|
||||||
|
import io.kamax.mxisd.config.threepid.medium.EmailTemplateConfig;
|
||||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||||
|
import io.kamax.mxisd.threepid.session.IThreePidSession;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.lang.WordUtils;
|
import org.apache.commons.lang.WordUtils;
|
||||||
@@ -34,55 +35,68 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class EmailInviteContentGenerator implements IInviteContentGenerator {
|
public class EmailNotificationGenerator implements IEmailNotificationGenerator {
|
||||||
|
|
||||||
private EmailConfig cfg;
|
private EmailConfig cfg;
|
||||||
private EmailInviteConfig invCfg;
|
private EmailTemplateConfig templateCfg;
|
||||||
private MatrixConfig mxCfg;
|
private MatrixConfig mxCfg;
|
||||||
private ApplicationContext app;
|
private ApplicationContext app;
|
||||||
|
|
||||||
@Autowired // FIXME ApplicationContext shouldn't be injected, find another way from config (?)
|
@Autowired // FIXME ApplicationContext shouldn't be injected, find another way from config (?)
|
||||||
public EmailInviteContentGenerator(EmailConfig cfg, EmailInviteConfig invCfg, MatrixConfig mxCfg, ApplicationContext app) {
|
public EmailNotificationGenerator(EmailConfig cfg, EmailTemplateConfig templateCfg, MatrixConfig mxCfg, ApplicationContext app) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
this.invCfg = invCfg;
|
this.templateCfg = templateCfg;
|
||||||
this.mxCfg = mxCfg;
|
this.mxCfg = mxCfg;
|
||||||
this.app = app;
|
this.app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMedium() {
|
public String getId() {
|
||||||
return ThreePidMedium.Email.getId();
|
return "template";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTemplateContent(String location) throws IOException {
|
||||||
|
InputStream is = StringUtils.startsWith(location, "classpath:") ?
|
||||||
|
app.getResource(location).getInputStream() : new FileInputStream(location);
|
||||||
|
return IOUtils.toString(is, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String populateCommon(String content, ThreePid recipient) {
|
||||||
|
String domainPretty = WordUtils.capitalizeFully(mxCfg.getDomain());
|
||||||
|
|
||||||
|
content = content.replace("%DOMAIN%", mxCfg.getDomain());
|
||||||
|
content = content.replace("%DOMAIN_PRETTY%", domainPretty);
|
||||||
|
content = content.replace("%FROM_EMAIL%", cfg.getIdentity().getFrom());
|
||||||
|
content = content.replace("%FROM_NAME%", cfg.getIdentity().getName());
|
||||||
|
content = content.replace("%RECIPIENT_MEDIUM%", recipient.getMedium());
|
||||||
|
content = content.replace("%RECIPIENT_ADDRESS%", recipient.getAddress());
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTemplateAndPopulate(String location, ThreePid recipient) throws IOException {
|
||||||
|
return populateCommon(getTemplateContent(location), recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generate(IThreePidInviteReply invite) {
|
public String get(IThreePidInviteReply invite) {
|
||||||
if (!ThreePidMedium.Email.is(invite.getInvite().getMedium())) {
|
|
||||||
throw new IllegalArgumentException(invite.getInvite().getMedium() + " is not a supported 3PID type");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String domainPretty = WordUtils.capitalizeFully(mxCfg.getDomain());
|
ThreePid tpid = new ThreePid(invite.getInvite().getMedium(), invite.getInvite().getAddress());
|
||||||
|
String templateBody = getTemplateAndPopulate(templateCfg.getInvite(), tpid);
|
||||||
|
|
||||||
String senderName = invite.getInvite().getProperties().getOrDefault("sender_display_name", "");
|
String senderName = invite.getInvite().getProperties().getOrDefault("sender_display_name", "");
|
||||||
String senderNameOrId = StringUtils.defaultIfBlank(senderName, invite.getInvite().getSender().getId());
|
String senderNameOrId = StringUtils.defaultIfBlank(senderName, invite.getInvite().getSender().getId());
|
||||||
String roomName = invite.getInvite().getProperties().getOrDefault("room_name", "");
|
String roomName = invite.getInvite().getProperties().getOrDefault("room_name", "");
|
||||||
String roomNameOrId = StringUtils.defaultIfBlank(roomName, invite.getInvite().getRoomId());
|
String roomNameOrId = StringUtils.defaultIfBlank(roomName, invite.getInvite().getRoomId());
|
||||||
|
|
||||||
String templateBody = IOUtils.toString(
|
|
||||||
StringUtils.startsWith(invCfg.getTemplate(), "classpath:") ?
|
|
||||||
app.getResource(invCfg.getTemplate()).getInputStream() : new FileInputStream(invCfg.getTemplate()),
|
|
||||||
StandardCharsets.UTF_8);
|
|
||||||
templateBody = templateBody.replace("%DOMAIN%", mxCfg.getDomain());
|
|
||||||
templateBody = templateBody.replace("%DOMAIN_PRETTY%", domainPretty);
|
|
||||||
templateBody = templateBody.replace("%FROM_EMAIL%", cfg.getFrom());
|
|
||||||
templateBody = templateBody.replace("%FROM_NAME%", cfg.getName());
|
|
||||||
templateBody = templateBody.replace("%SENDER_ID%", invite.getInvite().getSender().getId());
|
templateBody = templateBody.replace("%SENDER_ID%", invite.getInvite().getSender().getId());
|
||||||
templateBody = templateBody.replace("%SENDER_NAME%", senderName);
|
templateBody = templateBody.replace("%SENDER_NAME%", senderName);
|
||||||
templateBody = templateBody.replace("%SENDER_NAME_OR_ID%", senderNameOrId);
|
templateBody = templateBody.replace("%SENDER_NAME_OR_ID%", senderNameOrId);
|
||||||
templateBody = templateBody.replace("%INVITE_MEDIUM%", invite.getInvite().getMedium());
|
templateBody = templateBody.replace("%INVITE_MEDIUM%", tpid.getMedium());
|
||||||
templateBody = templateBody.replace("%INVITE_ADDRESS%", invite.getInvite().getAddress());
|
templateBody = templateBody.replace("%INVITE_ADDRESS%", tpid.getAddress());
|
||||||
templateBody = templateBody.replace("%ROOM_ID%", invite.getInvite().getRoomId());
|
templateBody = templateBody.replace("%ROOM_ID%", invite.getInvite().getRoomId());
|
||||||
templateBody = templateBody.replace("%ROOM_NAME%", roomName);
|
templateBody = templateBody.replace("%ROOM_NAME%", roomName);
|
||||||
templateBody = templateBody.replace("%ROOM_NAME_OR_ID%", roomNameOrId);
|
templateBody = templateBody.replace("%ROOM_NAME_OR_ID%", roomNameOrId);
|
||||||
@@ -93,4 +107,14 @@ public class EmailInviteContentGenerator implements IInviteContentGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getForValidation(IThreePidSession session) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getForRemotePublishingValidation(IThreePidSession session) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.threepid.notification.email;
|
||||||
|
|
||||||
|
import io.kamax.matrix.ThreePidMedium;
|
||||||
|
import io.kamax.mxisd.config.threepid.medium.EmailConfig;
|
||||||
|
import io.kamax.mxisd.exception.ConfigurationException;
|
||||||
|
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||||
|
import io.kamax.mxisd.notification.INotificationHandler;
|
||||||
|
import io.kamax.mxisd.threepid.connector.email.IEmailConnector;
|
||||||
|
import io.kamax.mxisd.threepid.session.IThreePidSession;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EmailNotificationHandler implements INotificationHandler {
|
||||||
|
|
||||||
|
private EmailConfig cfg;
|
||||||
|
private IEmailNotificationGenerator generator;
|
||||||
|
private IEmailConnector connector;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public EmailNotificationHandler(EmailConfig cfg, List<IEmailNotificationGenerator> generators, List<IEmailConnector> connectors) {
|
||||||
|
generator = generators.stream()
|
||||||
|
.filter(o -> StringUtils.equals(cfg.getGenerator(), o.getId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new ConfigurationException("Email notification generator [" + cfg.getGenerator() + "] could not be found"));
|
||||||
|
|
||||||
|
connector = connectors.stream()
|
||||||
|
.filter(o -> StringUtils.equals(cfg.getConnector(), o.getId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new ConfigurationException("Email sender connector [" + cfg.getConnector() + "] could not be found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMedium() {
|
||||||
|
return ThreePidMedium.Email.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notify(IThreePidInviteReply invite) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notify(IThreePidSession session) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2017 Maxime Dor
|
||||||
|
*
|
||||||
|
* https://max.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.threepid.notification.email;
|
||||||
|
|
||||||
|
import io.kamax.matrix.ThreePidMedium;
|
||||||
|
import io.kamax.mxisd.threepid.notification.INotificationGenerator;
|
||||||
|
|
||||||
|
public interface IEmailNotificationGenerator extends INotificationGenerator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String getMedium() {
|
||||||
|
return ThreePidMedium.Email.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -29,8 +29,6 @@ public interface IThreePidSession {
|
|||||||
|
|
||||||
String getId();
|
String getId();
|
||||||
|
|
||||||
String getHash();
|
|
||||||
|
|
||||||
Instant getCreationTime();
|
Instant getCreationTime();
|
||||||
|
|
||||||
String getServer();
|
String getServer();
|
||||||
@@ -43,6 +41,8 @@ public interface IThreePidSession {
|
|||||||
|
|
||||||
Optional<String> getNextLink();
|
Optional<String> getNextLink();
|
||||||
|
|
||||||
|
String getToken();
|
||||||
|
|
||||||
void validate(String token);
|
void validate(String token);
|
||||||
|
|
||||||
boolean isValidated();
|
boolean isValidated();
|
||||||
|
@@ -113,6 +113,11 @@ public class ThreePidSession implements IThreePidSession {
|
|||||||
return Optional.ofNullable(nextLink);
|
return Optional.ofNullable(nextLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void setAttempt(int attempt) {
|
public synchronized void setAttempt(int attempt) {
|
||||||
if (isValidated()) {
|
if (isValidated()) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
|
@@ -63,18 +63,25 @@ forward:
|
|||||||
- "https://vector.im"
|
- "https://vector.im"
|
||||||
|
|
||||||
threepid:
|
threepid:
|
||||||
email:
|
|
||||||
connector:
|
|
||||||
active: 'smtp'
|
|
||||||
provider:
|
|
||||||
smtp:
|
|
||||||
port: 587
|
|
||||||
tls: 1
|
|
||||||
|
|
||||||
invite:
|
|
||||||
medium:
|
medium:
|
||||||
email:
|
email:
|
||||||
template: 'classpath:email/invite-template.eml'
|
identity:
|
||||||
|
from: ''
|
||||||
|
name: ''
|
||||||
|
connector: 'smtp'
|
||||||
|
generator: 'template'
|
||||||
|
connectors:
|
||||||
|
smtp:
|
||||||
|
host: ''
|
||||||
|
port: 587
|
||||||
|
tls: 1
|
||||||
|
login: ''
|
||||||
|
password: ''
|
||||||
|
generators:
|
||||||
|
template:
|
||||||
|
invite: 'classpath:email/invite-template.eml'
|
||||||
|
session:
|
||||||
|
validation: 'classpath:email/validate-template.eml'
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
backend: 'sqlite'
|
backend: 'sqlite'
|
||||||
|
66
src/main/resources/email/validate-template.eml
Normal file
66
src/main/resources/email/validate-template.eml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
Subject: Your Matrix Validation Token
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: multipart/alternative;
|
||||||
|
boundary="7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ"
|
||||||
|
|
||||||
|
--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Disposition: inline
|
||||||
|
|
||||||
|
Hello,
|
||||||
|
|
||||||
|
We have received a request to link this email address with a Matrix account.
|
||||||
|
If this was you who made this request, you may use the following link to complete the verification of your email address:
|
||||||
|
|
||||||
|
%VALIDATION_LINK%
|
||||||
|
|
||||||
|
If your client requires a code, the code is %VALIDATION_TOKEN%
|
||||||
|
|
||||||
|
If you aren't aware of making such a request, please disregard this email.
|
||||||
|
|
||||||
|
Regards,
|
||||||
|
%DOMAIN_PRETTY% Admins
|
||||||
|
|
||||||
|
--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Disposition: inline
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title></title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Myriad Pro", "Myriad", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 12pt;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Hello,</p>
|
||||||
|
|
||||||
|
<p>We have received a request to link this email address with a Matrix account.
|
||||||
|
If this was you who made this request, you may use the following link to
|
||||||
|
complete the verification of your email address:</p>
|
||||||
|
|
||||||
|
<p><a href=%VALIDATION_LINK%">Complete email verification</a></p>
|
||||||
|
|
||||||
|
<p>...or copy this link into your web browser:</p>
|
||||||
|
|
||||||
|
<p>%VALIDATION_LINK%</p>
|
||||||
|
|
||||||
|
<p>If your client requires a code, the code is %VALIDATION_TOKEN%</p>
|
||||||
|
|
||||||
|
<p>If you aren't aware of making such a request, please disregard this
|
||||||
|
email.</p>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<p>Regards,<br>
|
||||||
|
%DOMAIN_PRETTY% Admins</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ--
|
Reference in New Issue
Block a user