Compare commits

...

12 Commits

Author SHA1 Message Date
Max Dor
cd890d114a Add warning about possibly unresolvable 3PID invites 2019-05-14 00:49:07 +02:00
Max Dor
321ba1e325 Code formatting (cosmetic, no-op) 2019-05-14 00:39:12 +02:00
Max Dor
c3ce0a17f6 Avoid conflict between 3PID expired user and Matrix ID users event 2019-05-13 16:08:35 +02:00
Max Dor
0fcc0d9bb2 Properly inform about bad configuration for 3PID builtin configs 2019-05-13 14:04:11 +02:00
Max Dor
ce7f900543 Make various optimisations/clarifications
- Change some log levels to be less verbose
- Add privacy link
- Remove unused code
2019-05-06 23:28:38 +02:00
Max Dor
c7c009f9af Fix indentation in builtin 3PID templates (cosmetic) 2019-05-06 19:16:20 +02:00
Max Dor
3b01663245 Switch to Gradle 5 build 2019-05-05 15:56:51 +02:00
Max Dor
9cc601d582 Fix custom config for custom notification handlers 2019-05-05 13:54:12 +02:00
Max Dor
e6272b1827 Improve detection and fast-fail on empty Sendgrid template paths 2019-05-05 13:48:14 +02:00
Max Dor
8243354f39 Remove unused but bug-triggering code block (Fix #172) 2019-05-04 11:17:36 +02:00
Max Dor
25968e0737 Log denied requests due to invalid credentials in AS 2019-05-04 11:16:19 +02:00
Max Dor
44a80461a0 Ensure lookup signatures are produced in a consistent way 2019-04-28 08:55:23 +02:00
21 changed files with 359 additions and 244 deletions

View File

@@ -48,6 +48,8 @@ def dockerImageTag = "${dockerImageName}:${mxisdVersion()}"
group = 'io.kamax' group = 'io.kamax'
mainClassName = 'io.kamax.mxisd.MxisdStandaloneExec' mainClassName = 'io.kamax.mxisd.MxisdStandaloneExec'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
String mxisdVersion() { String mxisdVersion() {
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?") def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
@@ -87,10 +89,10 @@ repositories {
dependencies { dependencies {
// Logging // Logging
compile 'org.slf4j:slf4j-simple:1.7.25' compile 'org.slf4j:slf4j-simple:1.7.25'
// Easy file management // Easy file management
compile 'commons-io:commons-io:2.5' compile 'commons-io:commons-io:2.5'
// Config management // Config management
compile 'org.yaml:snakeyaml:1.23' compile 'org.yaml:snakeyaml:1.23'
@@ -145,7 +147,7 @@ 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 // Command parser for AS interface
implementation 'commons-cli:commons-cli:1.4' implementation 'commons-cli:commons-cli:1.4'
@@ -158,7 +160,7 @@ dependencies {
jar { jar {
manifest { manifest {
attributes( attributes(
'Implementation-Version': mxisdVersion() 'Implementation-Version': mxisdVersion()
) )
} }
} }

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Fri Aug 11 17:19:02 CEST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip

18
gradlew vendored
View File

@@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
## Gradle start up script for UN*X ## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"

184
gradlew.bat vendored
View File

@@ -1,84 +1,100 @@
@if "%DEBUG%" == "" @echo off @rem
@rem ########################################################################## @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Gradle startup script for Windows @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem @rem you may not use this file except in compliance with the License.
@rem ########################################################################## @rem You may obtain a copy of the License at
@rem
@rem Set local scope for the variables with windows NT shell @rem http://www.apache.org/licenses/LICENSE-2.0
if "%OS%"=="Windows_NT" setlocal @rem
@rem Unless required by applicable law or agreed to in writing, software
set DIRNAME=%~dp0 @rem distributed under the License is distributed on an "AS IS" BASIS,
if "%DIRNAME%" == "" set DIRNAME=. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
set APP_BASE_NAME=%~n0 @rem See the License for the specific language governing permissions and
set APP_HOME=%DIRNAME% @rem limitations under the License.
@rem
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= @if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem Find java.exe @rem
if defined JAVA_HOME goto findJavaFromJavaHome @rem Gradle startup script for Windows
@rem
set JAVA_EXE=java.exe @rem ##########################################################################
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. set DIRNAME=%~dp0
echo. if "%DIRNAME%" == "" set DIRNAME=.
echo Please set the JAVA_HOME variable in your environment to match the set APP_BASE_NAME=%~n0
echo location of your Java installation. set APP_HOME=%DIRNAME%
goto fail @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% @rem Find java.exe
set JAVA_EXE=%JAVA_HOME%/bin/java.exe if defined JAVA_HOME goto findJavaFromJavaHome
if exist "%JAVA_EXE%" goto init set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
echo. if "%ERRORLEVEL%" == "0" goto init
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo location of your Java installation. echo.
echo Please set the JAVA_HOME variable in your environment to match the
goto fail echo location of your Java installation.
:init goto fail
@rem Get command-line arguments, handling Windows variants
:findJavaFromJavaHome
if not "%OS%" == "Windows_NT" goto win9xME_args set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
:win9xME_args
@rem Slurp the command line arguments. if exist "%JAVA_EXE%" goto init
set CMD_LINE_ARGS=
set _SKIP=2 echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
:win9xME_args_slurp echo.
if "x%~1" == "x" goto execute echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
set CMD_LINE_ARGS=%*
goto fail
:execute
@rem Setup the command line :init
@rem Get command-line arguments, handling Windows variants
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
if not "%OS%" == "Windows_NT" goto win9xME_args
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :win9xME_args
@rem Slurp the command line arguments.
:end set CMD_LINE_ARGS=
@rem End local scope for the variables with windows NT shell set _SKIP=2
if "%ERRORLEVEL%"=="0" goto mainEnd
:win9xME_args_slurp
:fail if "x%~1" == "x" goto execute
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! set CMD_LINE_ARGS=%*
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1 :execute
@rem Setup the command line
:mainEnd
if "%OS%"=="Windows_NT" endlocal set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:omega @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -118,7 +118,7 @@ public class Mxisd {
idStrategy = new RecursivePriorityLookupStrategy(cfg.getLookup(), ThreePidProviders.get(), bridgeFetcher); idStrategy = new RecursivePriorityLookupStrategy(cfg.getLookup(), ThreePidProviders.get(), bridgeFetcher);
pMgr = new ProfileManager(ProfileProviders.get(), clientDns, httpClient); pMgr = new ProfileManager(ProfileProviders.get(), clientDns, httpClient);
notifMgr = new NotificationManager(cfg.getNotification(), NotificationHandlers.get()); notifMgr = new NotificationManager(cfg.getNotification(), NotificationHandlers.get());
sessMgr = new SessionManager(cfg.getSession(), cfg.getMatrix(), store, notifMgr, idStrategy, httpClient); sessMgr = new SessionManager(cfg.getSession(), cfg.getMatrix(), store, notifMgr, idStrategy);
invMgr = new InvitationManager(cfg, store, idStrategy, keyMgr, signMgr, resolver, notifMgr, pMgr); invMgr = new InvitationManager(cfg, store, idStrategy, keyMgr, signMgr, resolver, notifMgr, pMgr);
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());

View File

@@ -176,10 +176,12 @@ public class AppSvcManager {
ensureEnabled(); ensureEnabled();
if (StringUtils.isBlank(token)) { if (StringUtils.isBlank(token)) {
log.info("Denying request without a HS token");
throw new HttpMatrixException(401, "M_UNAUTHORIZED", "No HS token"); throw new HttpMatrixException(401, "M_UNAUTHORIZED", "No HS token");
} }
if (!StringUtils.equals(cfg.getEndpoint().getToAS().getToken(), token)) { if (!StringUtils.equals(cfg.getEndpoint().getToAS().getToken(), token)) {
log.info("Denying request with an invalid HS token");
throw new NotAllowedException("Invalid HS token"); throw new NotAllowedException("Invalid HS token");
} }

View File

@@ -27,7 +27,6 @@ import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid; 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.mxisd.Mxisd; 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;
@@ -81,7 +80,7 @@ public class MembershipEventProcessor implements EventTypeProcessor {
_MatrixID target = MatrixID.asAcceptable(targetId); _MatrixID target = MatrixID.asAcceptable(targetId);
if (!StringUtils.equals(target.getDomain(), cfg.getMatrix().getDomain())) { if (!StringUtils.equals(target.getDomain(), cfg.getMatrix().getDomain())) {
log.debug("Ignoring invite for {}: not a local user"); log.debug("Ignoring invite for {}: not a local user", targetId);
return; return;
} }
@@ -89,10 +88,9 @@ public class MembershipEventProcessor implements EventTypeProcessor {
boolean isForMainUser = StringUtils.equals(target.getLocalPart(), cfg.getAppsvc().getUser().getMain()); boolean isForMainUser = StringUtils.equals(target.getLocalPart(), cfg.getAppsvc().getUser().getMain());
boolean isForExpInvUser = StringUtils.equals(target.getLocalPart(), cfg.getAppsvc().getUser().getInviteExpired()); boolean isForExpInvUser = StringUtils.equals(target.getLocalPart(), cfg.getAppsvc().getUser().getInviteExpired());
boolean isUs = isForMainUser || isForExpInvUser;
if (StringUtils.equals("join", EventKey.Membership.getStringOrNull(content))) { if (StringUtils.equals("join", EventKey.Membership.getStringOrNull(content))) {
if (!isForMainUser) { if (isForExpInvUser) {
log.warn("We joined the room {} for another identity as the main user, which is not supported. Leaving...", roomId); log.warn("We joined the room {} for another identity as the main user, which is not supported. Leaving...", roomId);
client.getUser(target.getLocalPart()).getRoom(roomId).tryLeave().ifPresent(err -> { client.getUser(target.getLocalPart()).getRoom(roomId).tryLeave().ifPresent(err -> {
@@ -108,10 +106,7 @@ public class MembershipEventProcessor implements EventTypeProcessor {
processForUserIdInvite(roomId, sender, target); processForUserIdInvite(roomId, sender, target);
} }
} else if (StringUtils.equals("leave", EventKey.Membership.getStringOrNull(content))) { } else if (StringUtils.equals("leave", EventKey.Membership.getStringOrNull(content))) {
_MatrixRoom room = client.getRoom(roomId); // TODO we need to find out if this is only us remaining and leave the room if so, using the right client for it
if (!isUs && room.getJoinedUsers().size() == 1) {
// TODO we need to find out if this is only us remaining and leave the room if so, using the right client for it
}
} else { } else {
log.debug("This is not an supported type of membership event, skipping"); log.debug("This is not an supported type of membership event, skipping");
} }

View File

@@ -20,7 +20,6 @@
package io.kamax.mxisd.config.threepid.notification; package io.kamax.mxisd.config.threepid.notification;
import com.google.gson.JsonObject;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.mxisd.threepid.notification.email.EmailRawNotificationHandler; import io.kamax.mxisd.threepid.notification.email.EmailRawNotificationHandler;
import io.kamax.mxisd.threepid.notification.phone.PhoneNotificationHandler; import io.kamax.mxisd.threepid.notification.phone.PhoneNotificationHandler;
@@ -35,7 +34,7 @@ public class NotificationConfig {
private transient final Logger log = LoggerFactory.getLogger(NotificationConfig.class); private transient final Logger log = LoggerFactory.getLogger(NotificationConfig.class);
private Map<String, String> handler = new HashMap<>(); private Map<String, String> handler = new HashMap<>();
private Map<String, JsonObject> handlers = new HashMap<>(); private Map<String, Object> handlers = new HashMap<>();
public NotificationConfig() { public NotificationConfig() {
handler.put(ThreePidMedium.Email.getId(), EmailRawNotificationHandler.ID); handler.put(ThreePidMedium.Email.getId(), EmailRawNotificationHandler.ID);
@@ -50,11 +49,11 @@ public class NotificationConfig {
this.handler = handler; this.handler = handler;
} }
public Map<String, JsonObject> getHandlers() { public Map<String, Object> getHandlers() {
return handlers; return handlers;
} }
public void setHandlers(Map<String, JsonObject> handlers) { public void setHandlers(Map<String, Object> handlers) {
this.handlers = handlers; this.handlers = handlers;
} }

View File

@@ -20,12 +20,45 @@
package io.kamax.mxisd.crypto; package io.kamax.mxisd.crypto;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.MatrixJson;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects;
public interface SignatureManager { public interface SignatureManager {
/**
* Sign the message and add the signature to the <code>signatures</code> key.
* <p>
* If the key does not exist yet, it is created. If the key exist, the produced signature will be merged with any
* existing ones.
*
* @param domain The domain under which the signature should be added
* @param message The message to sign and add the produced signature to
* @return The provided message with the new signature
* @throws IllegalArgumentException If the <code>signatures</code> value is not a JSON object
*/
default JsonObject signMessageGson(String domain, JsonObject message) throws IllegalArgumentException {
JsonElement signEl = message.remove(EventKey.Signatures.get());
JsonObject oldSigns = new JsonObject();
if (!Objects.isNull(signEl)) {
if (!signEl.isJsonObject()) {
throw new IllegalArgumentException("Message contains a signatures key that is not a JSON object value");
}
oldSigns = signEl.getAsJsonObject();
}
JsonObject newSigns = signMessageGson(domain, MatrixJson.encodeCanonical(message));
oldSigns.entrySet().forEach(entry -> newSigns.add(entry.getKey(), entry.getValue()));
message.add(EventKey.Signatures.get(), newSigns);
return message;
}
/** /**
* Sign the message and produce a <code>signatures</code> object that can directly be added to the object being signed. * Sign the message and produce a <code>signatures</code> object that can directly be added to the object being signed.
* *

View File

@@ -21,9 +21,7 @@
package io.kamax.mxisd.http.undertow.handler.identity.v1; package io.kamax.mxisd.http.undertow.handler.identity.v1;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.MatrixJson;
import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.config.ServerConfig; import io.kamax.mxisd.config.ServerConfig;
import io.kamax.mxisd.crypto.SignatureManager; import io.kamax.mxisd.crypto.SignatureManager;
@@ -73,11 +71,8 @@ public class SingleLookupHandler extends LookupHandler {
respondJson(exchange, "{}"); respondJson(exchange, "{}");
} else { } else {
SingleLookupReply lookup = lookupOpt.get(); SingleLookupReply lookup = lookupOpt.get();
// FIXME signing should be done in the business model, not in the controller
JsonObject obj = GsonUtil.makeObj(new SingeLookupReplyJson(lookup)); JsonObject obj = GsonUtil.makeObj(new SingeLookupReplyJson(lookup));
obj.add(EventKey.Signatures.get(), signMgr.signMessageGson(cfg.getName(), MatrixJson.encodeCanonical(obj))); signMgr.signMessageGson(cfg.getName(), obj);
respondJson(exchange, obj); respondJson(exchange, obj);
} }
} }

View File

@@ -111,11 +111,11 @@ public class InvitationManager {
this.notifMgr = notifMgr; this.notifMgr = notifMgr;
this.profileMgr = profileMgr; this.profileMgr = profileMgr;
log.info("Loading saved invites"); log.debug("Loading saved invites");
Collection<ThreePidInviteIO> ioList = storage.getInvites(); Collection<ThreePidInviteIO> ioList = storage.getInvites();
ioList.forEach(io -> { ioList.forEach(io -> {
io.getProperties().putIfAbsent(CreatedAtPropertyKey, defaultCreateTs); io.getProperties().putIfAbsent(CreatedAtPropertyKey, defaultCreateTs);
log.info("Processing invite {}", GsonUtil.get().toJson(io)); log.debug("Processing invite {}", GsonUtil.get().toJson(io));
ThreePidInvite invite = new ThreePidInvite( ThreePidInvite invite = new ThreePidInvite(
MatrixID.asAcceptable(io.getSender()), MatrixID.asAcceptable(io.getSender()),
io.getMedium(), io.getMedium(),
@@ -127,6 +127,7 @@ public class InvitationManager {
ThreePidInviteReply reply = new ThreePidInviteReply(io.getId(), invite, io.getToken(), "", Collections.emptyList()); ThreePidInviteReply reply = new ThreePidInviteReply(io.getId(), invite, io.getToken(), "", Collections.emptyList());
invitations.put(reply.getId(), reply); invitations.put(reply.getId(), reply);
}); });
log.info("Loaded saved invites");
// FIXME export such madness into matrix-java-sdk with a nice wrapper to talk to a homeserver // FIXME export such madness into matrix-java-sdk with a nice wrapper to talk to a homeserver
try { try {
@@ -511,6 +512,9 @@ public class InvitationManager {
publishMapping(reply, lookup.getMxid().getId()); publishMapping(reply, lookup.getMxid().getId());
} else { } else {
log.info("No mapping for pending invite {}", getIdForLog(reply)); log.info("No mapping for pending invite {}", getIdForLog(reply));
if (lookupMgr.getLocalProviders().isEmpty()) {
log.warn("No Identity store has been configured, this invite may never resolve");
}
} }
} catch (Throwable t) { } catch (Throwable t) {
log.error("Unable to process invite", t); log.error("Unable to process invite", t);

View File

@@ -40,7 +40,6 @@ import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
import io.kamax.mxisd.threepid.session.ThreePidSession; import io.kamax.mxisd.threepid.session.ThreePidSession;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -58,23 +57,18 @@ public class SessionManager {
private NotificationManager notifMgr; private NotificationManager notifMgr;
private LookupStrategy lookupMgr; private LookupStrategy lookupMgr;
// FIXME export into central class, set version
private CloseableHttpClient client;
public SessionManager( public SessionManager(
SessionConfig cfg, SessionConfig cfg,
MatrixConfig mxCfg, MatrixConfig mxCfg,
IStorage storage, IStorage storage,
NotificationManager notifMgr, NotificationManager notifMgr,
LookupStrategy lookupMgr, LookupStrategy lookupMgr
CloseableHttpClient client
) { ) {
this.cfg = cfg; this.cfg = cfg;
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
this.storage = storage; this.storage = storage;
this.notifMgr = notifMgr; this.notifMgr = notifMgr;
this.lookupMgr = lookupMgr; this.lookupMgr = lookupMgr;
this.client = client;
} }
private ThreePidSession getSession(String sid, String secret) { private ThreePidSession getSession(String sid, String secret) {
@@ -128,7 +122,7 @@ public class SessionManager {
log.info("Generated new session {} to validate {} from server {}", sessionId, tpid, server); log.info("Generated new session {} to validate {} from server {}", sessionId, tpid, server);
storage.insertThreePidSession(session.getDao()); storage.insertThreePidSession(session.getDao());
log.info("Stored session {}", sessionId, tpid, server); log.info("Stored session {}", sessionId);
log.info("Session {} for {}: sending validation notification", sessionId, tpid); log.info("Session {} for {}: sending validation notification", sessionId, tpid);
notifMgr.sendForValidation(session); notifMgr.sendForValidation(session);
@@ -196,6 +190,7 @@ public class SessionManager {
*/ */
log.warn("A remote host attempted to unbind without proper authorization. Request was denied"); log.warn("A remote host attempted to unbind without proper authorization. Request was denied");
log.warn("See https://github.com/kamax-matrix/mxisd/wiki/mxisd-and-your-privacy for more info");
if (!cfg.getPolicy().getUnbind().getFraudulent().getSendWarning()) { if (!cfg.getPolicy().getUnbind().getFraudulent().getSendWarning()) {
log.info("Not sending notification to 3PID owner as per configuration"); log.info("Not sending notification to 3PID owner as per configuration");

View File

@@ -27,8 +27,8 @@ import io.kamax.mxisd.http.IsAPIv1;
import io.kamax.mxisd.invitation.IMatrixIdInvite; import io.kamax.mxisd.invitation.IMatrixIdInvite;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.threepid.session.IThreePidSession; import io.kamax.mxisd.threepid.session.IThreePidSession;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils; import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.StringUtils;
import static io.kamax.mxisd.http.io.identity.StoreInviteRequest.Keys.RoomName; import static io.kamax.mxisd.http.io.identity.StoreInviteRequest.Keys.RoomName;
import static io.kamax.mxisd.http.io.identity.StoreInviteRequest.Keys.SenderDisplayName; import static io.kamax.mxisd.http.io.identity.StoreInviteRequest.Keys.SenderDisplayName;
@@ -46,6 +46,10 @@ public abstract class PlaceholderNotificationGenerator {
} }
protected String populateForCommon(ThreePid recipient, String input) { protected String populateForCommon(ThreePid recipient, String input) {
if (StringUtils.isBlank(input)) {
return input;
}
String domainPretty = WordUtils.capitalizeFully(mxCfg.getDomain()); String domainPretty = WordUtils.capitalizeFully(mxCfg.getDomain());
return input return input
@@ -56,6 +60,10 @@ public abstract class PlaceholderNotificationGenerator {
} }
protected String populateForInvite(IMatrixIdInvite invite, String input) { protected String populateForInvite(IMatrixIdInvite invite, String input) {
if (StringUtils.isBlank(input)) {
return input;
}
String senderName = invite.getProperties().getOrDefault(SenderDisplayName, ""); String senderName = invite.getProperties().getOrDefault(SenderDisplayName, "");
String senderNameOrId = StringUtils.defaultIfBlank(senderName, invite.getSender().getId()); String senderNameOrId = StringUtils.defaultIfBlank(senderName, invite.getSender().getId());
String roomName = invite.getProperties().getOrDefault(RoomName, ""); String roomName = invite.getProperties().getOrDefault(RoomName, "");
@@ -72,6 +80,10 @@ public abstract class PlaceholderNotificationGenerator {
} }
protected String populateForReply(IThreePidInviteReply invite, String input) { protected String populateForReply(IThreePidInviteReply invite, String input) {
if (StringUtils.isBlank(input)) {
return input;
}
ThreePid tpid = new ThreePid(invite.getInvite().getMedium(), invite.getInvite().getAddress()); ThreePid tpid = new ThreePid(invite.getInvite().getMedium(), invite.getInvite().getAddress());
String senderName = invite.getInvite().getProperties().getOrDefault(SenderDisplayName, ""); String senderName = invite.getInvite().getProperties().getOrDefault(SenderDisplayName, "");
@@ -93,6 +105,10 @@ public abstract class PlaceholderNotificationGenerator {
} }
protected String populateForValidation(IThreePidSession session, String input) { protected String populateForValidation(IThreePidSession session, String input) {
if (StringUtils.isBlank(input)) {
return input;
}
String validationLink = srvCfg.getPublicUrl() + IsAPIv1.getValidate( String validationLink = srvCfg.getPublicUrl() + IsAPIv1.getValidate(
session.getThreePid().getMedium(), session.getThreePid().getMedium(),
session.getId(), session.getId(),

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.threepid.notification; package io.kamax.mxisd.threepid.notification;
import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
@@ -65,13 +65,18 @@ public class BuiltInNotificationHandlerSupplier implements NotificationHandlerSu
if (StringUtils.equals(EmailRawNotificationHandler.ID, handler)) { if (StringUtils.equals(EmailRawNotificationHandler.ID, handler)) {
Object o = mxisd.getConfig().getThreepid().getMedium().get(ThreePidMedium.Email.getId()); Object o = mxisd.getConfig().getThreepid().getMedium().get(ThreePidMedium.Email.getId());
if (Objects.nonNull(o)) { if (Objects.nonNull(o)) {
EmailConfig emailCfg = GsonUtil.get().fromJson(GsonUtil.makeObj(o), EmailConfig.class); EmailConfig emailCfg;
try {
emailCfg = GsonUtil.get().fromJson(GsonUtil.makeObj(o), EmailConfig.class);
} catch (JsonSyntaxException e) {
throw new ConfigurationException("Invalid configuration for threepid email notification");
}
if (org.apache.commons.lang.StringUtils.isBlank(emailCfg.getGenerator())) { if (StringUtils.isBlank(emailCfg.getGenerator())) {
throw new ConfigurationException("notification.email.generator"); throw new ConfigurationException("notification.email.generator");
} }
if (org.apache.commons.lang.StringUtils.isBlank(emailCfg.getConnector())) { if (StringUtils.isBlank(emailCfg.getConnector())) {
throw new ConfigurationException("notification.email.connector"); throw new ConfigurationException("notification.email.connector");
} }
@@ -94,9 +99,15 @@ public class BuiltInNotificationHandlerSupplier implements NotificationHandlerSu
} }
if (StringUtils.equals(EmailSendGridNotificationHandler.ID, handler)) { if (StringUtils.equals(EmailSendGridNotificationHandler.ID, handler)) {
JsonObject cfgJson = mxisd.getConfig().getNotification().getHandlers().get(EmailSendGridNotificationHandler.ID); Object cfgJson = mxisd.getConfig().getNotification().getHandlers().get(EmailSendGridNotificationHandler.ID);
if (Objects.nonNull(cfgJson)) { if (Objects.nonNull(cfgJson)) {
EmailSendGridConfig cfg = GsonUtil.get().fromJson(cfgJson, EmailSendGridConfig.class); EmailSendGridConfig cfg;
try {
cfg = GsonUtil.get().fromJson(GsonUtil.get().toJson(cfgJson), EmailSendGridConfig.class);
} catch (JsonSyntaxException e) {
throw new ConfigurationException("Invalid configuration for threepid email sendgrid handler");
}
NotificationHandlers.register(() -> new EmailSendGridNotificationHandler(mxisd.getConfig(), cfg)); NotificationHandlers.register(() -> new EmailSendGridNotificationHandler(mxisd.getConfig(), cfg));
} }
} }
@@ -107,7 +118,12 @@ public class BuiltInNotificationHandlerSupplier implements NotificationHandlerSu
if (StringUtils.equals(PhoneNotificationHandler.ID, handler)) { if (StringUtils.equals(PhoneNotificationHandler.ID, handler)) {
Object o = mxisd.getConfig().getThreepid().getMedium().get(ThreePidMedium.PhoneNumber.getId()); Object o = mxisd.getConfig().getThreepid().getMedium().get(ThreePidMedium.PhoneNumber.getId());
if (Objects.nonNull(o)) { if (Objects.nonNull(o)) {
PhoneConfig cfg = GsonUtil.get().fromJson(GsonUtil.makeObj(o), PhoneConfig.class); PhoneConfig cfg;
try {
cfg = GsonUtil.get().fromJson(GsonUtil.makeObj(o), PhoneConfig.class);
} catch (JsonSyntaxException e) {
throw new ConfigurationException("Invalid configuration for threepid msisdn notification");
}
List<PhoneGenerator> generators = StreamSupport List<PhoneGenerator> generators = StreamSupport
.stream(ServiceLoader.load(PhoneGeneratorSupplier.class).spliterator(), false) .stream(ServiceLoader.load(PhoneGeneratorSupplier.class).spliterator(), false)

View File

@@ -33,7 +33,7 @@ import io.kamax.mxisd.notification.NotificationHandler;
import io.kamax.mxisd.threepid.generator.PlaceholderNotificationGenerator; import io.kamax.mxisd.threepid.generator.PlaceholderNotificationGenerator;
import io.kamax.mxisd.threepid.session.IThreePidSession; import io.kamax.mxisd.threepid.session.IThreePidSession;
import io.kamax.mxisd.util.FileUtil; import io.kamax.mxisd.util.FileUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -86,6 +86,9 @@ public class EmailSendGridNotificationHandler extends PlaceholderNotificationGen
@Override @Override
public void sendForInvite(IMatrixIdInvite invite) { public void sendForInvite(IMatrixIdInvite invite) {
EmailTemplate template = cfg.getTemplates().getGeneric().get("matrixId"); EmailTemplate template = cfg.getTemplates().getGeneric().get("matrixId");
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for Matrix ID invite notifications");
}
Email email = getEmail(); Email email = getEmail();
email.setSubject(populateForInvite(invite, template.getSubject())); email.setSubject(populateForInvite(invite, template.getSubject()));
@@ -98,6 +101,10 @@ public class EmailSendGridNotificationHandler extends PlaceholderNotificationGen
@Override @Override
public void sendForReply(IThreePidInviteReply invite) { public void sendForReply(IThreePidInviteReply invite) {
EmailTemplate template = cfg.getTemplates().getInvite(); EmailTemplate template = cfg.getTemplates().getInvite();
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for 3PID invite notifications");
}
Email email = getEmail(); Email email = getEmail();
email.setSubject(populateForReply(invite, template.getSubject())); email.setSubject(populateForReply(invite, template.getSubject()));
email.setText(populateForReply(invite, getFromFile(template.getBody().getText()))); email.setText(populateForReply(invite, getFromFile(template.getBody().getText())));
@@ -109,6 +116,10 @@ public class EmailSendGridNotificationHandler extends PlaceholderNotificationGen
@Override @Override
public void sendForValidation(IThreePidSession session) { public void sendForValidation(IThreePidSession session) {
EmailTemplate template = cfg.getTemplates().getSession().getValidation(); EmailTemplate template = cfg.getTemplates().getSession().getValidation();
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for validation notifications");
}
Email email = getEmail(); Email email = getEmail();
email.setSubject(populateForValidation(session, template.getSubject())); email.setSubject(populateForValidation(session, template.getSubject()));
email.setText(populateForValidation(session, getFromFile(template.getBody().getText()))); email.setText(populateForValidation(session, getFromFile(template.getBody().getText())));
@@ -120,6 +131,10 @@ public class EmailSendGridNotificationHandler extends PlaceholderNotificationGen
@Override @Override
public void sendForFraudulentUnbind(ThreePid tpid) { public void sendForFraudulentUnbind(ThreePid tpid) {
EmailTemplate template = cfg.getTemplates().getSession().getUnbind().getFraudulent(); EmailTemplate template = cfg.getTemplates().getSession().getUnbind().getFraudulent();
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for fraudulent unbind notifications");
}
Email email = getEmail(); Email email = getEmail();
email.setSubject(populateForCommon(tpid, template.getSubject())); email.setSubject(populateForCommon(tpid, template.getSubject()));
email.setText(populateForCommon(tpid, getFromFile(template.getBody().getText()))); email.setText(populateForCommon(tpid, getFromFile(template.getBody().getText())));

View File

@@ -39,26 +39,26 @@ Content-Disposition: inline
<html lang="en"> <html lang="en">
<head> <head>
<style type="text/css"> <style type="text/css">
body { body {
margin: 0px; margin: 0px;
} }
pre, code { pre, code {
word-break: break-word; word-break: break-word;
white-space: pre-wrap; white-space: pre-wrap;
} }
#page { #page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-color: #454545; font-color: #454545;
font-size: 12pt; font-size: 12pt;
width: 100%%; width: 100%%;
padding: 20px; padding: 20px;
} }
#inner { #inner {
width: 640px; width: 640px;
} }
</style> </style>
</head> </head>
<body> <body>
@@ -66,24 +66,24 @@ pre, code {
<tr> <tr>
<td> </td> <td> </td>
<td id="inner"> <td id="inner">
<p>Hi,</p> <p>Hi,</p>
<p>%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on <p>%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on
Matrix. To join the conversation, register an account on <a href="%REGISTER_URL%">%DOMAIN%</a>.</p> Matrix. To join the conversation, register an account on <a href="%REGISTER_URL%">%DOMAIN%</a>.</p>
<pYou can also register an account on a public server and get in touch with them.</p> <pYou can also register an account on a public server and get in touch with them.</p>
<br> <br>
<p>About Matrix:</p> <p>About Matrix:</p>
<p>Matrix is an open standard for interoperable, decentralised, real-time communication <p>Matrix is an open standard for interoperable, decentralised, real-time communication
over IP, supporting group chat, file transfer, voice and video calling, integrations to over IP, supporting group chat, file transfer, voice and video calling, integrations to
other apps, bridges to other communication systems and much more. It can be used to power other apps, bridges to other communication systems and much more. It can be used to power
Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication.</p> Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication.</p>
<p>Thanks,</p> <p>Thanks,</p>
<p>%DOMAIN_PRETTY% Admins</p> <p>%DOMAIN_PRETTY% Admins</p>
</td> </td>
<td> </td> <td> </td>
</tr> </tr>

View File

@@ -28,26 +28,26 @@ Content-Disposition: inline
<html lang="en"> <html lang="en">
<head> <head>
<style type="text/css"> <style type="text/css">
body { body {
margin: 0px; margin: 0px;
} }
pre, code { pre, code {
word-break: break-word; word-break: break-word;
white-space: pre-wrap; white-space: pre-wrap;
} }
#page { #page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-color: #454545; font-color: #454545;
font-size: 12pt; font-size: 12pt;
width: 100%%; width: 100%%;
padding: 20px; padding: 20px;
} }
#inner { #inner {
width: 640px; width: 640px;
} }
</style> </style>
</head> </head>
<body> <body>
@@ -55,13 +55,13 @@ pre, code {
<tr> <tr>
<td> </td> <td> </td>
<td id="inner"> <td id="inner">
<p>Hi,</p> <p>Hi,</p>
<p>%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on Matrix.</p> <p>%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on Matrix.</p>
<p>Thanks,</p> <p>Thanks,</p>
<p>%DOMAIN_PRETTY% Admins</p> <p>%DOMAIN_PRETTY% Admins</p>
</td> </td>
<td> </td> <td> </td>
</tr> </tr>

View File

@@ -61,26 +61,26 @@ Content-Disposition: inline
<html lang="en"> <html lang="en">
<head> <head>
<style type="text/css"> <style type="text/css">
body { body {
margin: 0px; margin: 0px;
} }
pre, code { pre, code {
word-break: break-word; word-break: break-word;
white-space: pre-wrap; white-space: pre-wrap;
} }
#page { #page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-color: #454545; font-color: #454545;
font-size: 12pt; font-size: 12pt;
width: 100%%; width: 100%%;
padding: 20px; padding: 20px;
} }
#inner { #inner {
width: 640px; width: 640px;
} }
</style> </style>
</head> </head>
<body> <body>
@@ -88,42 +88,42 @@ pre, code {
<tr> <tr>
<td> </td> <td> </td>
<td id="inner"> <td id="inner">
<p>Hi,</p> <p>Hi,</p>
<p><b>THIS IS IMPORTANT, PLEASE READ CAREFULLY</b>.<br/> <p><b>THIS IS IMPORTANT, PLEASE READ CAREFULLY</b>.<br/>
If you are the system administrator of the Matrix installation, read the second section.</p> If you are the system administrator of the Matrix installation, read the second section.</p>
<p>This is a notification email that a possibly unauthorized entity has attempted to alter your <p>This is a notification email that a possibly unauthorized entity has attempted to alter your
3PIDs (email, phone numbers, etc.) settings. The request was denied and no change has been made.</p> 3PIDs (email, phone numbers, etc.) settings. The request was denied and no change has been made.</p>
<p>This is so you are aware of a possible failure in case you just tried to remove a 3PID from your account.</p> <p>This is so you are aware of a possible failure in case you just tried to remove a 3PID from your account.</p>
<p>If you do not understand this email, please forward it to your System administrator.</p> <p>If you do not understand this email, please forward it to your System administrator.</p>
<hr> <hr>
<p>As the system administrator:</p> <p>As the system administrator:</p>
<p>If you are using synapse as a Homeserver, this is a known issue related to <a href="https://github.com/matrix-org/matrix-doc/issues/1194">MSC1194</a> <p>If you are using synapse as a Homeserver, this is a known issue related to <a href="https://github.com/matrix-org/matrix-doc/issues/1194">MSC1194</a>
and abuse of separation of concerns. As a privacy-centric product and to protect your privacy, the request was actively and abuse of separation of concerns. As a privacy-centric product and to protect your privacy, the request was actively
blocked. We have written a more detailed explanation on our <a href="https://github.com/kamax-matrix/mxisd/wiki/mxisd-and-your-privacy">Privacy wiki page</a> blocked. We have written a more detailed explanation on our <a href="https://github.com/kamax-matrix/mxisd/wiki/mxisd-and-your-privacy">Privacy wiki page</a>
(<a href="https://github.com/kamax-matrix/mxisd/wiki/mxisd-and-your-privacy#msc1194-synapse-and-impacts-on-your-privacy">Direct link to section</a>) (<a href="https://github.com/kamax-matrix/mxisd/wiki/mxisd-and-your-privacy#msc1194-synapse-and-impacts-on-your-privacy">Direct link to section</a>)
so you can fully grasp the impact for you and your users.</p> so you can fully grasp the impact for you and your users.</p>
<p>We have open an issue on the synapse repos to reflect the related privacy concerns and GDPR violation(s) and would <p>We have open an issue on the synapse repos to reflect the related privacy concerns and GDPR violation(s) and would
appreciate if you could comment on it or simply adds a thumbs up so the concerns are finally dealt with by the synapse dev team.<br/> appreciate if you could comment on it or simply adds a thumbs up so the concerns are finally dealt with by the synapse dev team.<br/>
Issue: <a href="https://github.com/matrix-org/synapse/issues/4540">https://github.com/matrix-org/synapse/issues/4540</a></p> Issue: <a href="https://github.com/matrix-org/synapse/issues/4540">https://github.com/matrix-org/synapse/issues/4540</a></p>
<p>If you are using another Homeserver or this came following no action from your own users, then you have been the target <p>If you are using another Homeserver or this came following no action from your own users, then you have been the target
of an unbind attack from a rogue entity which was blocked. You may want to check your logs to see the exact source of of an unbind attack from a rogue entity which was blocked. You may want to check your logs to see the exact source of
the attack and take relevant actions following your policy.</p> the attack and take relevant actions following your policy.</p>
<p>If you would like to disable these notifications, please see the <p>If you would like to disable these notifications, please see the
<a href="https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/session/session.md#configuration">3PID sessions configuration documentation.</a></p> <a href="https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/session/session.md#configuration">3PID sessions configuration documentation.</a></p>
<p>Thanks,</p> <p>Thanks,</p>
<p>%DOMAIN_PRETTY% Admins</p> <p>%DOMAIN_PRETTY% Admins</p>
</td> </td>
<td> </td> <td> </td>
</tr> </tr>

View File

@@ -33,30 +33,30 @@ Content-Disposition: inline
<html lang="en"> <html lang="en">
<head> <head>
<style type="text/css"> <style type="text/css">
body { body {
margin: 0px; margin: 0px;
} }
pre, code { pre, code {
word-break: break-word; word-break: break-word;
white-space: pre-wrap; white-space: pre-wrap;
} }
#page { #page {
font-family: 'Open Sans', Helvetica, Arial, Sans-Serif; font-family: 'Open Sans', Helvetica, Arial, Sans-Serif;
font-color: #454545; font-color: #454545;
font-size: 12pt; font-size: 12pt;
width: 100%%; width: 100%%;
padding: 20px; padding: 20px;
} }
#inner { #inner {
width: 640px; width: 640px;
} }
.notif_link a, .footer a { .notif_link a, .footer a {
color: #76CFA6 ! important; color: #76CFA6 ! important;
} }
</style> </style>
</head> </head>
<body> <body>

View File

@@ -21,6 +21,7 @@
package io.kamax.mxisd.test.crypto; package io.kamax.mxisd.test.crypto;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.MatrixJson; import io.kamax.matrix.json.MatrixJson;
import io.kamax.mxisd.crypto.Signature; import io.kamax.mxisd.crypto.Signature;
@@ -36,10 +37,14 @@ import org.junit.Test;
import static org.hamcrest.core.Is.is; import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
public class SignatureManagerTest { public class SignatureManagerTest {
private static final String lookupData = "{\n" + " \"not_before\": 0,\n" + " \"address\": \"mxisd-federation-test@kamax.io\",\n"
+ " \"medium\": \"email\",\n" + " \"mxid\": \"@mxisd-lookup-test:kamax.io\",\n"
+ " \"not_after\": 253402300799000,\n" + " \"ts\": 1523482030147\n" + "}";
private static SignatureManager signMgr; private static SignatureManager signMgr;
private static SignatureManager build(String keySeed) { private static SignatureManager build(String keySeed) {
@@ -98,12 +103,19 @@ public class SignatureManagerTest {
@Test @Test
public void onIdentityLookup() { public void onIdentityLookup() {
String value = MatrixJson.encodeCanonical("{\n" + " \"address\": \"mxisd-federation-test@kamax.io\",\n" String value = MatrixJson.encodeCanonical(lookupData);
+ " \"medium\": \"email\",\n" + " \"mxid\": \"@mxisd-lookup-test:kamax.io\",\n"
+ " \"not_after\": 253402300799000,\n" + " \"not_before\": 0,\n" + " \"ts\": 1523482030147\n" + "}");
String sign = "ObKA4PNQh2g6c7Yo2QcTcuDgIwhknG7ZfqmNYzbhrbLBOqZomU22xX9raufN2Y3ke1FXsDqsGs7WBDodmzZJCg"; String sign = "ObKA4PNQh2g6c7Yo2QcTcuDgIwhknG7ZfqmNYzbhrbLBOqZomU22xX9raufN2Y3ke1FXsDqsGs7WBDodmzZJCg";
testSign(value, sign); testSign(value, sign);
} }
@Test
public void onIdentityLookupFull() {
JsonObject data = GsonUtil.parseObj(lookupData);
signMgr.signMessageGson("localhost", data);
JsonObject signatures = EventKey.Signatures.getObj(data);
JsonObject domainSign = GsonUtil.getObj(signatures, "localhost");
String sign = GsonUtil.getStringOrThrow(domainSign, "ed25519:0");
assertEquals(sign, "ObKA4PNQh2g6c7Yo2QcTcuDgIwhknG7ZfqmNYzbhrbLBOqZomU22xX9raufN2Y3ke1FXsDqsGs7WBDodmzZJCg");
}
} }