Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
92f10347d1 | ||
|
0298f66212 | ||
|
0ddd086bda | ||
|
544f8e59f0 | ||
|
917f87bf8c | ||
|
774795c203 | ||
|
27b2976e42 | ||
|
f16f184253 |
@@ -19,29 +19,33 @@ All placeholders **MUST** be surrounded with `%` in the template. Per example, t
|
||||
### Global
|
||||
The following placeholders are available in every template:
|
||||
|
||||
| Placeholder | Purpose |
|
||||
|---------------------|------------------------------------------------------------------------------|
|
||||
| `DOMAIN` | Identity server authoritative domain, as configured in `matrix.domain` |
|
||||
| `DOMAIN_PRETTY` | Same as `DOMAIN` with the first letter upper case and all other lower case |
|
||||
| `FROM_EMAIL` | Email address configured in `threepid.medium.<3PID medium>.identity.from` |
|
||||
| `FROM_NAME` | Name configured in `threepid.medium.<3PID medium>.identity.name` |
|
||||
| `RECIPIENT_MEDIUM` | The 3PID medium, like `email` or `msisdn` |
|
||||
| `RECIPIENT_ADDRESS` | The address to which the notification is sent |
|
||||
| Placeholder | Purpose |
|
||||
|---------------------------------|------------------------------------------------------------------------------|
|
||||
| `DOMAIN` | Identity server authoritative domain, as configured in `matrix.domain` |
|
||||
| `DOMAIN_PRETTY` | Same as `DOMAIN` with the first letter upper case and all other lower case |
|
||||
| `FROM_EMAIL` | Email address configured in `threepid.medium.<3PID medium>.identity.from` |
|
||||
| `FROM_NAME` | Name configured in `threepid.medium.<3PID medium>.identity.name` |
|
||||
| `RECIPIENT_MEDIUM` | The 3PID medium, like `email` or `msisdn` |
|
||||
| `RECIPIENT_MEDIUM_URL_ENCODED` | URL encoded value of `RECIPIENT_MEDIUM` |
|
||||
| `RECIPIENT_ADDRESS` | The address to which the notification is sent |
|
||||
| `RECIPIENT_ADDRESS_URL_ENCODED` | URL encoded value of `RECIPIENT_ADDRESS` |
|
||||
|
||||
### Room invitation
|
||||
Specific placeholders:
|
||||
|
||||
| Placeholder | Purpose |
|
||||
|---------------------|------------------------------------------------------------------------------------------|
|
||||
| `SENDER_ID` | Matrix ID of the user who made the invite |
|
||||
| `SENDER_NAME` | Display name of the user who made the invite, if not available/set, empty |
|
||||
| `SENDER_NAME_OR_ID` | Display name of the user who made the invite. If not available/set, its Matrix ID |
|
||||
| `INVITE_MEDIUM` | The 3PID medium for the invite. |
|
||||
| `INVITE_ADDRESS` | The 3PID address for the invite. |
|
||||
| `ROOM_ID` | The Matrix ID of the Room in which the invite took place |
|
||||
| `ROOM_NAME` | The Name of the room in which the invite took place. If not available/set, empty |
|
||||
| `ROOM_NAME_OR_ID` | The Name of the room in which the invite took place. If not available/set, its Matrix ID |
|
||||
| `REGISTER_URL` | The URL to provide to the user allowing them to register their account, if needed |
|
||||
| Placeholder | Purpose |
|
||||
|------------------------------|-----------------------------------------------------------------------------------|
|
||||
| `SENDER_ID` | Matrix ID of the user who made the invite |
|
||||
| `SENDER_NAME` | Display name of the user who made the invite, if not available/set, empty |
|
||||
| `SENDER_NAME_OR_ID` | Display name of the user who made the invite. If not available/set, its Matrix ID |
|
||||
| `INVITE_MEDIUM` | The 3PID medium for the invite. |
|
||||
| `INVITE_MEDIUM_URL_ENCODED` | URL encoded value of `INVITE_MEDIUM` |
|
||||
| `INVITE_ADDRESS` | The 3PID address for the invite. |
|
||||
| `INVITE_ADDRESS_URL_ENCODED` | URL encoded value of `INVITE_ADDRESS` |
|
||||
| `ROOM_ID` | The Matrix ID of the Room in which the invite took place |
|
||||
| `ROOM_NAME` | The Name of the room in which the invite took place. If not available/set, empty |
|
||||
| `ROOM_NAME_OR_ID` | The Name of the room in which the invite took place. If not available/set, its ID |
|
||||
| `REGISTER_URL` | The URL to provide to the user allowing them to register their account, if needed |
|
||||
|
||||
### Validation of 3PID Session
|
||||
Specific placeholders:
|
||||
|
@@ -105,7 +105,7 @@ public class HttpMxisd {
|
||||
.get(SessionValidateHandler.Path, SaneHandler.around(new SessionValidationGetHandler(m.getSession(), m.getConfig())))
|
||||
.post(SessionValidateHandler.Path, SaneHandler.around(new SessionValidationPostHandler(m.getSession())))
|
||||
.get(SessionTpidGetValidatedHandler.Path, SaneHandler.around(new SessionTpidGetValidatedHandler(m.getSession())))
|
||||
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvite())))
|
||||
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvite(), m.getSign())))
|
||||
.post(SessionTpidUnbindHandler.Path, SaneHandler.around(new SessionTpidUnbindHandler(m.getSession())))
|
||||
.post(SignEd25519Handler.Path, SaneHandler.around(new SignEd25519Handler(m.getConfig(), m.getInvite(), m.getSign())))
|
||||
|
||||
|
@@ -107,7 +107,7 @@ public class Mxisd {
|
||||
|
||||
store = new OrmLiteSqlStorage(cfg);
|
||||
keyMgr = CryptoFactory.getKeyManager(cfg.getKey());
|
||||
signMgr = CryptoFactory.getSignatureManager(keyMgr);
|
||||
signMgr = CryptoFactory.getSignatureManager(cfg, keyMgr);
|
||||
clientDns = new ClientDnsOverwrite(cfg.getDns().getOverwrite());
|
||||
|
||||
synapse = new Synapse(cfg.getSynapseSql());
|
||||
|
@@ -64,6 +64,8 @@ import java.util.Objects;
|
||||
|
||||
public class AuthManager {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AuthManager.class);
|
||||
|
||||
private static final String TypeKey = "type";
|
||||
private static final String UserKey = "user";
|
||||
private static final String IdentifierKey = "identifier";
|
||||
@@ -72,7 +74,6 @@ public class AuthManager {
|
||||
private static final String UserIdTypeValue = "m.id.user";
|
||||
private static final String ThreepidTypeValue = "m.id.thirdparty";
|
||||
|
||||
private transient final Logger log = LoggerFactory.getLogger(AuthManager.class);
|
||||
private final Gson gson = GsonUtil.get(); // FIXME replace
|
||||
|
||||
private List<AuthenticatorProvider> providers;
|
||||
@@ -138,6 +139,12 @@ public class AuthManager {
|
||||
invMgr.publishMappingIfInvited(new ThreePidMapping(pid, mxId));
|
||||
}
|
||||
|
||||
try {
|
||||
MatrixID.asValid(mxId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("The returned User ID {} is not a valid Matrix ID. Login might fail at the Homeserver level", mxId);
|
||||
}
|
||||
|
||||
invMgr.lookupMappingsForInvites();
|
||||
|
||||
return authResult;
|
||||
|
@@ -83,6 +83,12 @@ public class MxisdConfig {
|
||||
|
||||
}
|
||||
|
||||
public static MxisdConfig forDomain(String domain) {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain(domain);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
private AppServiceConfig appsvc = new AppServiceConfig();
|
||||
private AuthenticationConfig auth = new AuthenticationConfig();
|
||||
private DirectoryConfig directory = new DirectoryConfig();
|
||||
@@ -309,6 +315,13 @@ public class MxisdConfig {
|
||||
this.wordpress = wordpress;
|
||||
}
|
||||
|
||||
public MxisdConfig inMemory() {
|
||||
getKey().setPath(":memory:");
|
||||
getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MxisdConfig build() {
|
||||
if (StringUtils.isBlank(getServer().getName())) {
|
||||
getServer().setName(getMatrix().getDomain());
|
||||
|
@@ -21,6 +21,7 @@
|
||||
package io.kamax.mxisd.crypto;
|
||||
|
||||
import io.kamax.mxisd.config.KeyConfig;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.crypto.ed25519.Ed25519KeyManager;
|
||||
import io.kamax.mxisd.crypto.ed25519.Ed25519SignatureManager;
|
||||
import io.kamax.mxisd.storage.crypto.FileKeyStore;
|
||||
@@ -54,8 +55,8 @@ public class CryptoFactory {
|
||||
return new Ed25519KeyManager(store);
|
||||
}
|
||||
|
||||
public static SignatureManager getSignatureManager(Ed25519KeyManager keyMgr) {
|
||||
return new Ed25519SignatureManager(keyMgr);
|
||||
public static SignatureManager getSignatureManager(MxisdConfig cfg, Ed25519KeyManager keyMgr) {
|
||||
return new Ed25519SignatureManager(cfg, keyMgr);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -30,6 +30,18 @@ import java.util.Objects;
|
||||
|
||||
public interface SignatureManager {
|
||||
|
||||
/**
|
||||
* Sign the message with the default domain 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 message The message to sign with the default domain and add the produced signature to
|
||||
* @return The provided message with the new signature
|
||||
* @throws IllegalArgumentException If the <code>signatures</code> key exists and its value is not a JSON object
|
||||
*/
|
||||
JsonObject signMessageGson(JsonObject message) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Sign the message and add the signature to the <code>signatures</code> key.
|
||||
* <p>
|
||||
@@ -39,7 +51,7 @@ public interface SignatureManager {
|
||||
* @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
|
||||
* @throws IllegalArgumentException If the <code>signatures</code> key exists and its value is not a JSON object
|
||||
*/
|
||||
default JsonObject signMessageGson(String domain, JsonObject message) throws IllegalArgumentException {
|
||||
JsonElement signEl = message.remove(EventKey.Signatures.get());
|
||||
|
@@ -23,6 +23,8 @@ package io.kamax.mxisd.crypto.ed25519;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.codec.MxBase64;
|
||||
import io.kamax.matrix.json.MatrixJson;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.config.ServerConfig;
|
||||
import io.kamax.mxisd.crypto.KeyIdentifier;
|
||||
import io.kamax.mxisd.crypto.Signature;
|
||||
import io.kamax.mxisd.crypto.SignatureManager;
|
||||
@@ -35,12 +37,19 @@ import java.security.SignatureException;
|
||||
|
||||
public class Ed25519SignatureManager implements SignatureManager {
|
||||
|
||||
private final ServerConfig cfg;
|
||||
private final Ed25519KeyManager keyMgr;
|
||||
|
||||
public Ed25519SignatureManager(Ed25519KeyManager keyMgr) {
|
||||
public Ed25519SignatureManager(MxisdConfig cfg, Ed25519KeyManager keyMgr) {
|
||||
this.cfg = cfg.getServer();
|
||||
this.keyMgr = keyMgr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject signMessageGson(JsonObject message) throws IllegalArgumentException {
|
||||
return signMessageGson(cfg.getName(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject signMessageGson(String domain, String message) {
|
||||
Signature sign = sign(message);
|
||||
|
@@ -33,8 +33,7 @@ public class InternalServerError extends HttpMatrixException {
|
||||
super(
|
||||
HttpStatus.SC_INTERNAL_SERVER_ERROR,
|
||||
"M_UNKNOWN",
|
||||
"An internal server error occured. If this error persists, please contact support with reference #" +
|
||||
Instant.now().toEpochMilli()
|
||||
"An internal server error occurred. Contact your administrator with reference Transaction #" + Instant.now().toEpochMilli()
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -97,7 +97,7 @@ public class SaneHandler extends BasicHttpHandler {
|
||||
if (StringUtils.isNotBlank(e.getInternalReason())) {
|
||||
log.error("Transaction #{} - {}", e.getReference(), e.getInternalReason());
|
||||
} else {
|
||||
log.error("Transaction #{}", e);
|
||||
log.error("Transaction #{}", e.getReference(), e);
|
||||
}
|
||||
|
||||
handleException(exchange, e);
|
||||
|
@@ -36,7 +36,7 @@ public class RestAuthHandler extends BasicHttpHandler {
|
||||
|
||||
public static final String Path = "/_matrix-internal/identity/v1/check_credentials";
|
||||
|
||||
private transient final Logger log = LoggerFactory.getLogger(RestAuthHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(RestAuthHandler.class);
|
||||
|
||||
private AuthManager mgr;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class RestAuthHandler extends BasicHttpHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(HttpServerExchange exchange) throws Exception {
|
||||
public void handleRequest(HttpServerExchange exchange) {
|
||||
JsonObject authData = parseJsonObject(exchange, "user");
|
||||
if (!authData.has("id") || !authData.has("password")) {
|
||||
throw new JsonMemberNotFoundException("Missing id or password keys");
|
||||
|
@@ -40,7 +40,7 @@ public class UserDirectorySearchHandler extends HomeserverProxyHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(HttpServerExchange exchange) throws Exception {
|
||||
public void handleRequest(HttpServerExchange exchange) {
|
||||
String accessToken = getAccessToken(exchange);
|
||||
UserDirectorySearchRequest searchQuery = parseJsonTo(exchange, UserDirectorySearchRequest.class);
|
||||
URI target = URI.create(exchange.getRequestURL());
|
||||
|
@@ -37,7 +37,7 @@ public class BulkLookupHandler extends LookupHandler {
|
||||
|
||||
public static final String Path = IsAPIv1.Base + "/bulk_lookup";
|
||||
|
||||
private transient final Logger log = LoggerFactory.getLogger(SingleLookupHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(SingleLookupHandler.class);
|
||||
|
||||
private LookupStrategy strategy;
|
||||
|
||||
|
@@ -31,7 +31,7 @@ public class EphemeralKeyIsValidHandler extends KeyIsValidHandler {
|
||||
|
||||
public static final String Path = IsAPIv1.Base + "/pubkey/ephemeral/isvalid";
|
||||
|
||||
private transient final Logger log = LoggerFactory.getLogger(EphemeralKeyIsValidHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(EphemeralKeyIsValidHandler.class);
|
||||
|
||||
private KeyManager mgr;
|
||||
|
||||
|
@@ -21,11 +21,15 @@
|
||||
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.crypto.SignatureManager;
|
||||
import io.kamax.mxisd.exception.BadRequestException;
|
||||
import io.kamax.mxisd.http.IsAPIv1;
|
||||
import io.kamax.mxisd.http.io.identity.BindRequest;
|
||||
import io.kamax.mxisd.http.io.identity.SingeLookupReplyJson;
|
||||
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
|
||||
import io.kamax.mxisd.invitation.InvitationManager;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.session.SessionManager;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.util.QueryParameterUtils;
|
||||
@@ -42,14 +46,16 @@ public class SessionTpidBindHandler extends BasicHttpHandler {
|
||||
|
||||
public static final String Path = IsAPIv1.Base + "/3pid/bind";
|
||||
|
||||
private transient final Logger log = LoggerFactory.getLogger(SessionTpidBindHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(SessionTpidBindHandler.class);
|
||||
|
||||
private SessionManager mgr;
|
||||
private InvitationManager invMgr;
|
||||
private SignatureManager signMgr;
|
||||
|
||||
public SessionTpidBindHandler(SessionManager mgr, InvitationManager invMgr) {
|
||||
public SessionTpidBindHandler(SessionManager mgr, InvitationManager invMgr, SignatureManager signMgr) {
|
||||
this.mgr = mgr;
|
||||
this.invMgr = invMgr;
|
||||
this.signMgr = signMgr;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,8 +80,9 @@ public class SessionTpidBindHandler extends BasicHttpHandler {
|
||||
}
|
||||
|
||||
try {
|
||||
mgr.bind(bindReq.getSid(), bindReq.getSecret(), bindReq.getUserId());
|
||||
respond(exchange, new JsonObject());
|
||||
SingleLookupReply lookup = mgr.bind(bindReq.getSid(), bindReq.getSecret(), bindReq.getUserId());
|
||||
JsonObject response = signMgr.signMessageGson(GsonUtil.makeObj(new SingeLookupReplyJson(lookup)));
|
||||
respond(exchange, response);
|
||||
} catch (BadRequestException e) {
|
||||
log.info("requested session was not validated");
|
||||
|
||||
|
@@ -72,7 +72,7 @@ public class SingleLookupReply {
|
||||
}
|
||||
|
||||
public SingleLookupReply(SingleLookupRequest request, _MatrixID mxid) {
|
||||
this(request, mxid, Instant.now(), Instant.ofEpochMilli(0), Instant.ofEpochMilli(253402300799000L));
|
||||
this(request, mxid, Instant.now(), Instant.now().minusSeconds(60), Instant.now().plusSeconds(5 * 60));
|
||||
}
|
||||
|
||||
public SingleLookupReply(SingleLookupRequest request, _MatrixID mxid, Instant timestamp, Instant notBefore, Instant notAfter) {
|
||||
|
@@ -79,7 +79,7 @@ public class IdentityServerUtils {
|
||||
|
||||
JsonElement el = parser.parse(IOUtils.toString(res.getEntity().getContent(), StandardCharsets.UTF_8));
|
||||
if (!el.isJsonObject()) {
|
||||
log.debug("IS {} did not send back an empty JSON object as per spec, not a valid IS");
|
||||
log.debug("IS {} did not send back an empty JSON object as per spec, not a valid IS", remote);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class IdentityServerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSrvRecordName(String domain) {
|
||||
private static String getSrvRecordName(String domain) {
|
||||
return "_matrix-identity._tcp." + domain;
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,7 @@ import io.kamax.mxisd.exception.NotImplementedException;
|
||||
import io.kamax.mxisd.exception.SessionNotValidatedException;
|
||||
import io.kamax.mxisd.exception.SessionUnknownException;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.lookup.SingleLookupRequest;
|
||||
import io.kamax.mxisd.lookup.ThreePidValidation;
|
||||
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
||||
import io.kamax.mxisd.notification.NotificationManager;
|
||||
@@ -151,7 +152,7 @@ public class SessionManager {
|
||||
return new ThreePidValidation(session.getThreePid(), session.getValidationTime());
|
||||
}
|
||||
|
||||
public void bind(String sid, String secret, String mxidRaw) {
|
||||
public SingleLookupReply bind(String sid, String secret, String mxidRaw) {
|
||||
// We make sure we have an acceptable User ID
|
||||
if (StringUtils.isEmpty(mxidRaw)) {
|
||||
throw new IllegalArgumentException("No Matrix User ID provided");
|
||||
@@ -165,11 +166,16 @@ public class SessionManager {
|
||||
|
||||
// Only accept binds if the domain matches our own
|
||||
if (!StringUtils.equalsIgnoreCase(mxCfg.getDomain(), mxid.getDomain())) {
|
||||
throw new NotAllowedException("Only Matrix IDs from domain " + mxCfg + " can be bound");
|
||||
throw new NotAllowedException("Only Matrix IDs from domain " + mxCfg.getDomain() + " can be bound");
|
||||
}
|
||||
|
||||
log.info("Session {}: Binding of {}:{} to Matrix ID {} is accepted",
|
||||
session.getId(), session.getThreePid().getMedium(), session.getThreePid().getAddress(), mxid.getId());
|
||||
|
||||
SingleLookupRequest request = new SingleLookupRequest();
|
||||
request.setType(session.getThreePid().getMedium());
|
||||
request.setThreePid(session.getThreePid().getAddress());
|
||||
return new SingleLookupReply(request, mxid);
|
||||
}
|
||||
|
||||
public void unbind(JsonObject reqData) {
|
||||
|
@@ -21,10 +21,12 @@
|
||||
package io.kamax.mxisd.threepid.connector.phone;
|
||||
|
||||
import com.twilio.Twilio;
|
||||
import com.twilio.exception.ApiException;
|
||||
import com.twilio.rest.api.v2010.account.Message;
|
||||
import com.twilio.type.PhoneNumber;
|
||||
import io.kamax.mxisd.config.threepid.connector.PhoneTwilioConfig;
|
||||
import io.kamax.mxisd.exception.BadRequestException;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import io.kamax.mxisd.exception.NotImplementedException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -52,12 +54,17 @@ public class PhoneSmsTwilioConnector implements PhoneConnector {
|
||||
@Override
|
||||
public void send(String recipient, String content) {
|
||||
if (StringUtils.isBlank(cfg.getAccountSid()) || StringUtils.isBlank(cfg.getAuthToken()) || StringUtils.isBlank(cfg.getNumber())) {
|
||||
throw new BadRequestException("Phone numbers cannot be validated at this time. Contact your administrator.");
|
||||
log.error("Twilio connector in not fully configured and is missing mandatory configuration values.");
|
||||
throw new NotImplementedException("Phone numbers cannot be validated at this time. Contact your administrator.");
|
||||
}
|
||||
|
||||
recipient = "+" + recipient;
|
||||
log.info("Sending SMS notification from {} to {} with {} characters", cfg.getNumber(), recipient, content.length());
|
||||
Message.creator(new PhoneNumber("+" + recipient), new PhoneNumber(cfg.getNumber()), content).create();
|
||||
try {
|
||||
Message.creator(new PhoneNumber("+" + recipient), new PhoneNumber(cfg.getNumber()), content).create();
|
||||
} catch (ApiException e) {
|
||||
throw new InternalServerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import io.kamax.mxisd.http.IsAPIv1;
|
||||
import io.kamax.mxisd.invitation.IMatrixIdInvite;
|
||||
import io.kamax.mxisd.invitation.IThreePidInviteReply;
|
||||
import io.kamax.mxisd.threepid.session.IThreePidSession;
|
||||
import io.kamax.mxisd.util.RestClientUtils;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -56,7 +57,9 @@ public abstract class PlaceholderNotificationGenerator {
|
||||
.replace("%DOMAIN%", mxCfg.getDomain())
|
||||
.replace("%DOMAIN_PRETTY%", domainPretty)
|
||||
.replace("%RECIPIENT_MEDIUM%", recipient.getMedium())
|
||||
.replace("%RECIPIENT_ADDRESS%", recipient.getAddress());
|
||||
.replace("%RECIPIENT_MEDIUM_URL_ENCODED%", RestClientUtils.urlEncode(recipient.getMedium()))
|
||||
.replace("%RECIPIENT_ADDRESS%", recipient.getAddress())
|
||||
.replace("%RECIPIENT_ADDRESS_URL_ENCODED%", RestClientUtils.urlEncode(recipient.getAddress()));
|
||||
}
|
||||
|
||||
protected String populateForInvite(IMatrixIdInvite invite, String input) {
|
||||
@@ -98,7 +101,9 @@ public abstract class PlaceholderNotificationGenerator {
|
||||
.replace("%SENDER_NAME%", senderName)
|
||||
.replace("%SENDER_NAME_OR_ID%", senderNameOrId)
|
||||
.replace("%INVITE_MEDIUM%", tpid.getMedium())
|
||||
.replace("%INVITE_MEDIUM_URL_ENCODED%", RestClientUtils.urlEncode(tpid.getMedium()))
|
||||
.replace("%INVITE_ADDRESS%", tpid.getAddress())
|
||||
.replace("%INVITE_ADDRESS_URL_ENCODED%", RestClientUtils.urlEncode(tpid.getAddress()))
|
||||
.replace("%ROOM_ID%", invite.getInvite().getRoomId())
|
||||
.replace("%ROOM_NAME%", roomName)
|
||||
.replace("%ROOM_NAME_OR_ID%", roomNameOrId);
|
||||
|
@@ -25,12 +25,22 @@ import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class RestClientUtils {
|
||||
|
||||
private static Gson gson = GsonUtil.build();
|
||||
|
||||
public static String urlEncode(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpPost post(String url, String body) {
|
||||
StringEntity entity = new StringEntity(body, StandardCharsets.UTF_8);
|
||||
entity.setContentType(ContentType.APPLICATION_JSON.toString());
|
||||
|
@@ -9,19 +9,12 @@ Content-Disposition: inline
|
||||
|
||||
Hi,
|
||||
|
||||
%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on
|
||||
Matrix. To join the conversation, register an account on %REGISTER_URL%
|
||||
%SENDER_NAME_OR_ID% has invited you to the Matrix room [%ROOM_NAME_OR_ID%].
|
||||
To join the conversation, register an account using %REGISTER_URL%
|
||||
|
||||
You may be required to provide the same email used for this invite during registration.
|
||||
You can also register an account on a public server and get in touch with them.
|
||||
|
||||
|
||||
About Matrix:
|
||||
|
||||
Matrix is an open standard for interoperable, decentralised, real-time communication
|
||||
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
|
||||
Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication.
|
||||
|
||||
Thanks,
|
||||
|
||||
%DOMAIN_PRETTY% Admins
|
||||
@@ -68,18 +61,11 @@ Content-Disposition: inline
|
||||
<td id="inner">
|
||||
<p>Hi,</p>
|
||||
|
||||
<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>
|
||||
<p>%SENDER_NAME_OR_ID% has invited you to the Matrix room [%ROOM_NAME_OR_ID%].<br/>
|
||||
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>
|
||||
|
||||
<br>
|
||||
<p>About Matrix:</p>
|
||||
|
||||
<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
|
||||
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>
|
||||
<p>You may be required to provide the same email used for this invite during registration.<br/>
|
||||
You can also register an account on a public server and get in touch with them.</p>
|
||||
|
||||
<p>Thanks,</p>
|
||||
|
||||
|
@@ -9,7 +9,7 @@ Content-Disposition: inline
|
||||
|
||||
Hi,
|
||||
|
||||
%SENDER_NAME_OR_ID% has invited you into a room [%ROOM_NAME_OR_ID%] on Matrix.
|
||||
%SENDER_NAME_OR_ID% has invited you to the Matrix room [%ROOM_NAME_OR_ID%].
|
||||
|
||||
Thanks,
|
||||
|
||||
@@ -57,7 +57,7 @@ Content-Disposition: inline
|
||||
<td id="inner">
|
||||
<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 to the Matrix room [%ROOM_NAME_OR_ID%].</p>
|
||||
|
||||
<p>Thanks,</p>
|
||||
|
||||
|
@@ -33,11 +33,7 @@ public class MxisdDefaultTest {
|
||||
|
||||
@Test
|
||||
public void defaultConfig() {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain(domain);
|
||||
cfg.getKey().setPath(":memory:");
|
||||
cfg.getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
|
||||
MxisdConfig cfg = MxisdConfig.forDomain(domain).inMemory();
|
||||
Mxisd m = new Mxisd(cfg);
|
||||
m.start();
|
||||
|
||||
|
@@ -41,10 +41,7 @@ public class MxisdTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain("localhost");
|
||||
cfg.getKey().setPath(":memory:");
|
||||
cfg.getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
MxisdConfig cfg = MxisdConfig.forDomain("localhost").inMemory();
|
||||
|
||||
MemoryThreePid mem3pid = new MemoryThreePid();
|
||||
mem3pid.setMedium("email");
|
||||
|
77
src/test/java/io/kamax/mxisd/test/auth/AuthManagerTest.java
Normal file
77
src/test/java/io/kamax/mxisd/test/auth/AuthManagerTest.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2019 Kamax Sarl
|
||||
*
|
||||
* https://www.kamax.io/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.test.auth;
|
||||
|
||||
import io.kamax.mxisd.Mxisd;
|
||||
import io.kamax.mxisd.auth.AuthManager;
|
||||
import io.kamax.mxisd.auth.UserAuthResult;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.config.memory.MemoryIdentityConfig;
|
||||
import io.kamax.mxisd.config.memory.MemoryThreePid;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class AuthManagerTest {
|
||||
|
||||
private static AuthManager mgr;
|
||||
|
||||
// FIXME we should be able to easily build the class ourselves
|
||||
// FIXME use constants
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain("localhost");
|
||||
cfg.getKey().setPath(":memory:");
|
||||
cfg.getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
|
||||
MemoryThreePid mem3pid = new MemoryThreePid();
|
||||
mem3pid.setMedium("email");
|
||||
mem3pid.setAddress("john@localhost");
|
||||
MemoryIdentityConfig validCfg = new MemoryIdentityConfig();
|
||||
validCfg.setUsername("john");
|
||||
validCfg.setPassword("doe");
|
||||
validCfg.getThreepids().add(mem3pid);
|
||||
MemoryIdentityConfig illegalUser = new MemoryIdentityConfig();
|
||||
illegalUser.setUsername("JANE");
|
||||
illegalUser.setPassword("doe");
|
||||
cfg.getMemory().setEnabled(true);
|
||||
cfg.getMemory().getIdentities().add(validCfg);
|
||||
cfg.getMemory().getIdentities().add(illegalUser);
|
||||
|
||||
Mxisd m = new Mxisd(cfg);
|
||||
m.start();
|
||||
mgr = m.getAuth();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basic() {
|
||||
UserAuthResult result = mgr.authenticate("@john:localhost", "doe");
|
||||
assertTrue(result.isSuccess());
|
||||
|
||||
// For backward-compatibility as per instructed by the spec, we do not fail on an illegal username
|
||||
// This makes sure we don't break it
|
||||
result = mgr.authenticate("@JANE:localhost", "doe");
|
||||
assertTrue(result.isSuccess());
|
||||
}
|
||||
|
||||
}
|
@@ -24,6 +24,7 @@ import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.event.EventKey;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.matrix.json.MatrixJson;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.crypto.Signature;
|
||||
import io.kamax.mxisd.crypto.SignatureManager;
|
||||
import io.kamax.mxisd.crypto.ed25519.Ed25519Key;
|
||||
@@ -52,7 +53,7 @@ public class SignatureManagerTest {
|
||||
KeyStore store = new MemoryKeyStore();
|
||||
store.add(key);
|
||||
|
||||
return new Ed25519SignatureManager(new Ed25519KeyManager(store));
|
||||
return new Ed25519SignatureManager(MxisdConfig.forDomain("localhost").inMemory().build(), new Ed25519KeyManager(store));
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2019 Kamax Sarl
|
||||
*
|
||||
* https://www.kamax.io/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.test.util;
|
||||
|
||||
import io.kamax.mxisd.util.RestClientUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class RestClientUtilsTest {
|
||||
|
||||
@Test
|
||||
public void urlEncode() {
|
||||
String encoded = RestClientUtils.urlEncode("john+doe@example.org");
|
||||
assertEquals("john%2Bdoe%40example.org", encoded);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user