Add the TOS API.

This commit is contained in:
Anatoly Sablin
2019-10-09 23:12:23 +03:00
parent baed894ff8
commit add6ed8fd9
6 changed files with 132 additions and 12 deletions

View File

@@ -59,6 +59,8 @@ import io.kamax.mxisd.http.undertow.handler.profile.v1.ProfileHandler;
import io.kamax.mxisd.http.undertow.handler.register.v1.Register3pidRequestTokenHandler; import io.kamax.mxisd.http.undertow.handler.register.v1.Register3pidRequestTokenHandler;
import io.kamax.mxisd.http.undertow.handler.status.StatusHandler; import io.kamax.mxisd.http.undertow.handler.status.StatusHandler;
import io.kamax.mxisd.http.undertow.handler.status.VersionHandler; import io.kamax.mxisd.http.undertow.handler.status.VersionHandler;
import io.kamax.mxisd.http.undertow.handler.term.v2.AcceptTermsHandler;
import io.kamax.mxisd.http.undertow.handler.term.v2.GetTermsHandler;
import io.kamax.mxisd.matrix.IdentityServiceAPI; import io.kamax.mxisd.matrix.IdentityServiceAPI;
import io.undertow.Handlers; import io.undertow.Handlers;
import io.undertow.Undertow; import io.undertow.Undertow;
@@ -66,6 +68,7 @@ import io.undertow.server.HttpHandler;
import io.undertow.server.RoutingHandler; import io.undertow.server.RoutingHandler;
import io.undertow.util.HttpString; import io.undertow.util.HttpString;
import io.undertow.util.Methods; import io.undertow.util.Methods;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -143,6 +146,7 @@ public class HttpMxisd {
.get(InternalInfoHandler.Path, SaneHandler.around(new InternalInfoHandler())); .get(InternalInfoHandler.Path, SaneHandler.around(new InternalInfoHandler()));
keyEndpoints(handler); keyEndpoints(handler);
identityEndpoints(handler); identityEndpoints(handler);
termsEndpoints(handler);
httpSrv = Undertow.builder().addHttpListener(m.getConfig().getServer().getPort(), "0.0.0.0").setHandler(handler).build(); httpSrv = Undertow.builder().addHttpListener(m.getConfig().getServer().getPort(), "0.0.0.0").setHandler(handler).build();
httpSrv.start(); httpSrv.start();
@@ -186,6 +190,12 @@ public class HttpMxisd {
); );
} }
private void termsEndpoints(RoutingHandler routingHandler) {
routingHandler.get(GetTermsHandler.PATH, new GetTermsHandler(m.getConfig().getPolicy()));
routingHandler
.post(AcceptTermsHandler.PATH, AuthorizationHandler.around(m.getAccMgr(), sane(new AcceptTermsHandler(m.getAccMgr()))));
}
private void addEndpoints(RoutingHandler routingHandler, HttpString method, boolean useAuthorization, ApiHandler... handlers) { private void addEndpoints(RoutingHandler routingHandler, HttpString method, boolean useAuthorization, ApiHandler... handlers) {
for (ApiHandler handler : handlers) { for (ApiHandler handler : handlers) {
attachHandler(routingHandler, method, handler, useAuthorization, sane(handler)); attachHandler(routingHandler, method, handler, useAuthorization, sane(handler));
@@ -199,23 +209,28 @@ public class HttpMxisd {
routingHandler.add(method, apiHandler.getPath(IdentityServiceAPI.V1), httpHandler); routingHandler.add(method, apiHandler.getPath(IdentityServiceAPI.V1), httpHandler);
} }
if (matrixConfig.isV2()) { if (matrixConfig.isV2()) {
PolicyConfig policyConfig = m.getConfig().getPolicy(); HttpHandler handlerWithTerms = CheckTermsHandler.around(m.getAccMgr(), httpHandler, getPolicyObjects(apiHandler));
List<PolicyConfig.PolicyObject> policies = new ArrayList<>();
if (!policyConfig.getPolicies().isEmpty()) {
for (PolicyConfig.PolicyObject policy : policyConfig.getPolicies().values()) {
for (Pattern pattern : policy.getPatterns()) {
if (pattern.matcher(apiHandler.getHandlerPath()).matches()) {
policies.add(policy);
}
}
}
}
HttpHandler handlerWithTerms = CheckTermsHandler.around(m.getAccMgr(), httpHandler, policies);
HttpHandler wrappedHandler = useAuthorization ? AuthorizationHandler.around(m.getAccMgr(), handlerWithTerms) : handlerWithTerms; HttpHandler wrappedHandler = useAuthorization ? AuthorizationHandler.around(m.getAccMgr(), handlerWithTerms) : handlerWithTerms;
routingHandler.add(method, apiHandler.getPath(IdentityServiceAPI.V2), wrappedHandler); routingHandler.add(method, apiHandler.getPath(IdentityServiceAPI.V2), wrappedHandler);
} }
} }
@NotNull
private List<PolicyConfig.PolicyObject> getPolicyObjects(ApiHandler apiHandler) {
PolicyConfig policyConfig = m.getConfig().getPolicy();
List<PolicyConfig.PolicyObject> policies = new ArrayList<>();
if (!policyConfig.getPolicies().isEmpty()) {
for (PolicyConfig.PolicyObject policy : policyConfig.getPolicies().values()) {
for (Pattern pattern : policy.getPatterns()) {
if (pattern.matcher(apiHandler.getHandlerPath()).matches()) {
policies.add(policy);
}
}
}
}
return policies;
}
private HttpHandler sane(HttpHandler httpHandler) { private HttpHandler sane(HttpHandler httpHandler) {
return SaneHandler.around(httpHandler); return SaneHandler.around(httpHandler);
} }

View File

@@ -138,6 +138,7 @@ public class AccountManager {
} }
public void deleteAccount(String token) { public void deleteAccount(String token) {
storage.deleteAccepts(token);
storage.deleteToken(token); storage.deleteToken(token);
} }

View File

@@ -0,0 +1,57 @@
package io.kamax.mxisd.http.undertow.handler.term.v2;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.auth.AccountManager;
import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.kamax.mxisd.storage.ormlite.dao.AccountDao;
import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AcceptTermsHandler extends BasicHttpHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AcceptTermsHandler.class);
public static final String PATH = "/_matrix/identity/v2/terms";
private final AccountManager accountManager;
public AcceptTermsHandler(AccountManager accountManager) {
this.accountManager = accountManager;
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
String token = getAccessToken(exchange);
JsonObject request = parseJsonObject(exchange);
JsonObject accepts = GsonUtil.getObj(request, "user_accepts");
AccountDao account = accountManager.findAccount(token);
if (account == null) {
throw new InvalidCredentialsException();
}
if (accepts == null || accepts.isJsonNull()) {
respondJson(exchange, "{}");
return;
}
if (accepts.isJsonArray()) {
for (JsonElement acceptItem : accepts.getAsJsonArray()) {
String termUrl = acceptItem.getAsString();
LOGGER.info("User {} accepts the term: {}", account.getUserId(), termUrl);
accountManager.acceptTerm(token, termUrl);
}
} else {
String termUrl = accepts.getAsString();
LOGGER.info("User {} accepts the term: {}", account.getUserId(), termUrl);
accountManager.acceptTerm(token, termUrl);
}
respondJson(exchange, "{}");
}
}

View File

@@ -0,0 +1,37 @@
package io.kamax.mxisd.http.undertow.handler.term.v2;
import com.google.gson.JsonObject;
import io.kamax.mxisd.config.PolicyConfig;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.undertow.server.HttpServerExchange;
import java.util.Map;
public class GetTermsHandler extends BasicHttpHandler {
public static final String PATH = "/_matrix/identity/v2/terms";
private final JsonObject policyResponse;
public GetTermsHandler(PolicyConfig config) {
policyResponse = new JsonObject();
JsonObject policies = new JsonObject();
for (Map.Entry<String, PolicyConfig.PolicyObject> policyItem : config.getPolicies().entrySet()) {
JsonObject policy = new JsonObject();
policy.addProperty("version", policyItem.getValue().getVersion());
for (Map.Entry<String, PolicyConfig.TermObject> termEntry : policyItem.getValue().getTerms().entrySet()) {
JsonObject term = new JsonObject();
term.addProperty("name", termEntry.getValue().getName());
term.addProperty("url", termEntry.getValue().getUrl());
policy.add(termEntry.getKey(), term);
}
policies.add(policyItem.getKey(), policy);
}
policyResponse.add("policies", policies);
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
respond(exchange, policyResponse);
}
}

View File

@@ -63,5 +63,7 @@ public interface IStorage {
void acceptTerm(String token, String url); void acceptTerm(String token, String url);
void deleteAccepts(String token);
boolean isTermAccepted(String token, List<PolicyConfig.PolicyObject> policies); boolean isTermAccepted(String token, List<PolicyConfig.PolicyObject> policies);
} }

View File

@@ -294,6 +294,14 @@ public class OrmLiteSqlStorage implements IStorage {
}); });
} }
@Override
public void deleteAccepts(String token) {
withCatcher(() -> {
AccountDao account = findAccount(token).orElseThrow(InvalidCredentialsException::new);
acceptedDao.delete(acceptedDao.queryForEq("userId", account.getUserId()));
});
}
@Override @Override
public boolean isTermAccepted(String token, List<PolicyConfig.PolicyObject> policies) { public boolean isTermAccepted(String token, List<PolicyConfig.PolicyObject> policies) {
return withCatcher(() -> { return withCatcher(() -> {