@@ -84,8 +84,8 @@ public class DefaultExceptionHandler {
|
|||||||
return handleGeneric(request, response, e);
|
return handleGeneric(request, response, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(MatrixException.class)
|
@ExceptionHandler(HttpMatrixException.class)
|
||||||
public String handleGeneric(HttpServletRequest request, HttpServletResponse response, MatrixException e) {
|
public String handleGeneric(HttpServletRequest request, HttpServletResponse response, HttpMatrixException e) {
|
||||||
response.setStatus(e.getStatus());
|
response.setStatus(e.getStatus());
|
||||||
return handle(request, e.getErrorCode(), e.getError());
|
return handle(request, e.getErrorCode(), e.getError());
|
||||||
}
|
}
|
||||||
|
54
src/main/java/io/kamax/mxisd/controller/ProxyController.java
Normal file
54
src/main/java/io/kamax/mxisd/controller/ProxyController.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2018 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.controller;
|
||||||
|
|
||||||
|
import io.kamax.mxisd.exception.AccessTokenNotFoundException;
|
||||||
|
import io.kamax.mxisd.util.OptionalUtil;
|
||||||
|
import org.thymeleaf.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class ProxyController {
|
||||||
|
|
||||||
|
private final static String headerName = "Authorization";
|
||||||
|
private final static String headerValuePrefix = "Bearer ";
|
||||||
|
private final static String parameterName = "access_token";
|
||||||
|
|
||||||
|
Optional<String> findAccessTokenInHeaders(HttpServletRequest request) {
|
||||||
|
return Optional.ofNullable(request.getHeader(headerName))
|
||||||
|
.filter(header -> StringUtils.startsWith(header, headerValuePrefix))
|
||||||
|
.map(header -> header.substring(headerValuePrefix.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<String> findAccessTokenInQuery(HttpServletRequest request) {
|
||||||
|
return Optional.ofNullable(request.getParameter(parameterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> findAccessToken(HttpServletRequest request) {
|
||||||
|
return OptionalUtil.findFirst(() -> findAccessTokenInHeaders(request), () -> findAccessTokenInQuery(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccessToken(HttpServletRequest request) {
|
||||||
|
return findAccessToken(request).orElseThrow(AccessTokenNotFoundException::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -21,6 +21,7 @@
|
|||||||
package io.kamax.mxisd.controller.directory.v1;
|
package io.kamax.mxisd.controller.directory.v1;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import io.kamax.mxisd.controller.ProxyController;
|
||||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
||||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||||
import io.kamax.mxisd.directory.DirectoryManager;
|
import io.kamax.mxisd.directory.DirectoryManager;
|
||||||
@@ -28,7 +29,10 @@ import io.kamax.mxisd.util.GsonParser;
|
|||||||
import io.kamax.mxisd.util.GsonUtil;
|
import io.kamax.mxisd.util.GsonUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -37,7 +41,7 @@ import java.net.URI;
|
|||||||
@RestController
|
@RestController
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@RequestMapping(path = "/_matrix/client/r0/user_directory", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
@RequestMapping(path = "/_matrix/client/r0/user_directory", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
public class UserDirectoryController {
|
public class UserDirectoryController extends ProxyController {
|
||||||
|
|
||||||
private Gson gson = GsonUtil.build();
|
private Gson gson = GsonUtil.build();
|
||||||
private GsonParser parser = new GsonParser(gson);
|
private GsonParser parser = new GsonParser(gson);
|
||||||
@@ -46,7 +50,8 @@ public class UserDirectoryController {
|
|||||||
private DirectoryManager mgr;
|
private DirectoryManager mgr;
|
||||||
|
|
||||||
@RequestMapping(path = "/search", method = RequestMethod.POST)
|
@RequestMapping(path = "/search", method = RequestMethod.POST)
|
||||||
public String search(HttpServletRequest request, @RequestParam("access_token") String accessToken) throws IOException {
|
public String search(HttpServletRequest request) throws IOException {
|
||||||
|
String accessToken = getAccessToken(request);
|
||||||
UserDirectorySearchRequest searchQuery = parser.parse(request, UserDirectorySearchRequest.class);
|
UserDirectorySearchRequest searchQuery = parser.parse(request, UserDirectorySearchRequest.class);
|
||||||
URI target = URI.create(request.getRequestURL().toString());
|
URI target = URI.create(request.getRequestURL().toString());
|
||||||
UserDirectorySearchResult result = mgr.search(target, accessToken, searchQuery.getSearchTerm());
|
UserDirectorySearchResult result = mgr.search(target, accessToken, searchQuery.getSearchTerm());
|
||||||
|
@@ -26,6 +26,7 @@ import com.google.gson.JsonObject;
|
|||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.kamax.matrix.MatrixID;
|
import io.kamax.matrix.MatrixID;
|
||||||
import io.kamax.matrix._ThreePid;
|
import io.kamax.matrix._ThreePid;
|
||||||
|
import io.kamax.mxisd.controller.ProxyController;
|
||||||
import io.kamax.mxisd.dns.ClientDnsOverwrite;
|
import io.kamax.mxisd.dns.ClientDnsOverwrite;
|
||||||
import io.kamax.mxisd.profile.ProfileManager;
|
import io.kamax.mxisd.profile.ProfileManager;
|
||||||
import io.kamax.mxisd.util.GsonUtil;
|
import io.kamax.mxisd.util.GsonUtil;
|
||||||
@@ -49,11 +50,12 @@ import java.io.IOException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@RequestMapping(path = "/_matrix/client/r0/profile", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
@RequestMapping(path = "/_matrix/client/r0/profile", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
public class ProfileController {
|
public class ProfileController extends ProxyController {
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(ProfileController.class);
|
private final Logger log = LoggerFactory.getLogger(ProfileController.class);
|
||||||
private final ProfileManager mgr;
|
private final ProfileManager mgr;
|
||||||
@@ -82,7 +84,11 @@ public class ProfileController {
|
|||||||
|
|
||||||
@RequestMapping("/{userId:.+}")
|
@RequestMapping("/{userId:.+}")
|
||||||
public String getProfile(HttpServletRequest req, HttpServletResponse res, @PathVariable String userId) {
|
public String getProfile(HttpServletRequest req, HttpServletResponse res, @PathVariable String userId) {
|
||||||
try (CloseableHttpResponse hsResponse = client.execute(new HttpGet(resolveProxyUrl(req)))) {
|
Optional<String> accessTokenOpt = findAccessToken(req);
|
||||||
|
HttpGet reqOut = new HttpGet(resolveProxyUrl(req));
|
||||||
|
accessTokenOpt.ifPresent(accessToken -> reqOut.addHeader("Authorization", "Bearer " + accessToken));
|
||||||
|
|
||||||
|
try (CloseableHttpResponse hsResponse = client.execute(reqOut)) {
|
||||||
res.setStatus(hsResponse.getStatusLine().getStatusCode());
|
res.setStatus(hsResponse.getStatusLine().getStatusCode());
|
||||||
JsonElement el = parser.parse(EntityUtils.toString(hsResponse.getEntity()));
|
JsonElement el = parser.parse(EntityUtils.toString(hsResponse.getEntity()));
|
||||||
List<_ThreePid> list = mgr.getThreepids(MatrixID.asAcceptable(userId));
|
List<_ThreePid> list = mgr.getThreepids(MatrixID.asAcceptable(userId));
|
||||||
|
@@ -27,8 +27,8 @@ import io.kamax.mxisd.config.DirectoryConfig;
|
|||||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
||||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||||
import io.kamax.mxisd.dns.ClientDnsOverwrite;
|
import io.kamax.mxisd.dns.ClientDnsOverwrite;
|
||||||
|
import io.kamax.mxisd.exception.HttpMatrixException;
|
||||||
import io.kamax.mxisd.exception.InternalServerError;
|
import io.kamax.mxisd.exception.InternalServerError;
|
||||||
import io.kamax.mxisd.exception.MatrixException;
|
|
||||||
import io.kamax.mxisd.util.GsonUtil;
|
import io.kamax.mxisd.util.GsonUtil;
|
||||||
import io.kamax.mxisd.util.RestClientUtils;
|
import io.kamax.mxisd.util.RestClientUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
@@ -99,7 +99,7 @@ public class DirectoryManager {
|
|||||||
log.warn("Homeserver does not support Directory feature, skipping");
|
log.warn("Homeserver does not support Directory feature, skipping");
|
||||||
} else {
|
} else {
|
||||||
log.error("Homeserver returned an error while performing directory search");
|
log.error("Homeserver returned an error while performing directory search");
|
||||||
throw new MatrixException(status, info.getErrcode(), info.getError());
|
throw new HttpMatrixException(status, info.getErrcode(), info.getError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2018 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.exception;
|
||||||
|
|
||||||
|
public class AccessTokenNotFoundException extends HttpMatrixException {
|
||||||
|
|
||||||
|
public AccessTokenNotFoundException() {
|
||||||
|
super(401, "M_UNKNOWN_TOKEN", "An access token is required to access this resource");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
|
||||||
public class FeatureNotAvailable extends MatrixException {
|
public class FeatureNotAvailable extends HttpMatrixException {
|
||||||
|
|
||||||
private String internalReason;
|
private String internalReason;
|
||||||
|
|
||||||
|
@@ -20,28 +20,19 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.exception;
|
package io.kamax.mxisd.exception;
|
||||||
|
|
||||||
public class MatrixException extends MxisdException {
|
import io.kamax.matrix.MatrixException;
|
||||||
|
|
||||||
|
public class HttpMatrixException extends MatrixException {
|
||||||
|
|
||||||
private int status;
|
private int status;
|
||||||
private String errorCode;
|
|
||||||
private String error;
|
|
||||||
|
|
||||||
public MatrixException(int status, String errorCode, String error) {
|
public HttpMatrixException(int status, String errorCode, String error) {
|
||||||
|
super(errorCode, error);
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.errorCode = errorCode;
|
|
||||||
this.error = error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStatus() {
|
public int getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getErrorCode() {
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getError() {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@@ -24,7 +24,7 @@ import org.apache.http.HttpStatus;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public class InternalServerError extends MatrixException {
|
public class InternalServerError extends HttpMatrixException {
|
||||||
|
|
||||||
private String reference = Long.toString(Instant.now().toEpochMilli());
|
private String reference = Long.toString(Instant.now().toEpochMilli());
|
||||||
private String internalReason;
|
private String internalReason;
|
||||||
|
@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
|
||||||
public class MessageForClientException extends MatrixException {
|
public class MessageForClientException extends HttpMatrixException {
|
||||||
|
|
||||||
public MessageForClientException(String error) {
|
public MessageForClientException(String error) {
|
||||||
super(HttpStatus.SC_OK, "M_MESSAGE_FOR_CLIENT", error);
|
super(HttpStatus.SC_OK, "M_MESSAGE_FOR_CLIENT", error);
|
||||||
|
@@ -23,7 +23,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
|
||||||
public class NotAllowedException extends MatrixException {
|
public class NotAllowedException extends HttpMatrixException {
|
||||||
|
|
||||||
public NotAllowedException(String s) {
|
public NotAllowedException(String s) {
|
||||||
super(HttpStatus.SC_FORBIDDEN, "M_FORBIDDEN", s);
|
super(HttpStatus.SC_FORBIDDEN, "M_FORBIDDEN", s);
|
||||||
|
@@ -2,7 +2,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
|
||||||
public class RemoteHomeServerException extends MatrixException {
|
public class RemoteHomeServerException extends HttpMatrixException {
|
||||||
|
|
||||||
public RemoteHomeServerException(String error) {
|
public RemoteHomeServerException(String error) {
|
||||||
super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_HS_ERROR", "Error from remote server: " + error);
|
super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_HS_ERROR", "Error from remote server: " + error);
|
||||||
|
@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
|
||||||
public class RemoteIdentityServerException extends MatrixException {
|
public class RemoteIdentityServerException extends HttpMatrixException {
|
||||||
|
|
||||||
public RemoteIdentityServerException(String error) {
|
public RemoteIdentityServerException(String error) {
|
||||||
super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_IS_ERROR", "Error from remote server: " + error);
|
super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_IS_ERROR", "Error from remote server: " + error);
|
||||||
|
@@ -23,7 +23,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
public class RemoteLoginException extends MatrixException {
|
public class RemoteLoginException extends HttpMatrixException {
|
||||||
|
|
||||||
private JsonObject errorBodyMsgResp;
|
private JsonObject errorBodyMsgResp;
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
|
|||||||
|
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
|
||||||
public class SessionNotValidatedException extends MatrixException {
|
public class SessionNotValidatedException extends HttpMatrixException {
|
||||||
|
|
||||||
public SessionNotValidatedException() {
|
public SessionNotValidatedException() {
|
||||||
super(HttpStatus.SC_OK, "M_SESSION_NOT_VALIDATED", "This validation session has not yet been completed");
|
super(HttpStatus.SC_OK, "M_SESSION_NOT_VALIDATED", "This validation session has not yet been completed");
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.exception;
|
package io.kamax.mxisd.exception;
|
||||||
|
|
||||||
public class SessionUnknownException extends MatrixException {
|
public class SessionUnknownException extends HttpMatrixException {
|
||||||
|
|
||||||
public SessionUnknownException() {
|
public SessionUnknownException() {
|
||||||
this("No valid session was found matching that sid and client secret");
|
this("No valid session was found matching that sid and client secret");
|
||||||
|
33
src/main/java/io/kamax/mxisd/util/OptionalUtil.java
Normal file
33
src/main/java/io/kamax/mxisd/util/OptionalUtil.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* mxisd - Matrix Identity Server Daemon
|
||||||
|
* Copyright (C) 2018 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.util;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class OptionalUtil {
|
||||||
|
|
||||||
|
public static <T> Optional<T> findFirst(Supplier<Optional<T>>... suppliers) {
|
||||||
|
return Stream.of(suppliers).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user