Add initial Hash configuration. Add the HashDetailsHandler.

This commit is contained in:
Anatoly Sablin
2019-10-15 23:38:32 +03:00
parent add6ed8fd9
commit 703044d06a
13 changed files with 338 additions and 10 deletions

View File

@@ -53,6 +53,7 @@ import io.kamax.mxisd.http.undertow.handler.identity.share.SessionValidationPost
import io.kamax.mxisd.http.undertow.handler.identity.share.SignEd25519Handler;
import io.kamax.mxisd.http.undertow.handler.identity.share.StoreInviteHandler;
import io.kamax.mxisd.http.undertow.handler.identity.v1.*;
import io.kamax.mxisd.http.undertow.handler.identity.v2.HashDetailsHandler;
import io.kamax.mxisd.http.undertow.handler.invite.v1.RoomInviteHandler;
import io.kamax.mxisd.http.undertow.handler.profile.v1.InternalProfileHandler;
import io.kamax.mxisd.http.undertow.handler.profile.v1.ProfileHandler;
@@ -147,6 +148,7 @@ public class HttpMxisd {
keyEndpoints(handler);
identityEndpoints(handler);
termsEndpoints(handler);
hashEndpoints(handler);
httpSrv = Undertow.builder().addHttpListener(m.getConfig().getServer().getPort(), "0.0.0.0").setHandler(handler).build();
httpSrv.start();
@@ -196,6 +198,10 @@ public class HttpMxisd {
.post(AcceptTermsHandler.PATH, AuthorizationHandler.around(m.getAccMgr(), sane(new AcceptTermsHandler(m.getAccMgr()))));
}
private void hashEndpoints(RoutingHandler routingHandler) {
routingHandler.get(HashDetailsHandler.PATH, AuthorizationHandler.around(m.getAccMgr(), sane(new HashDetailsHandler(m.getHashManager()))));
}
private void addEndpoints(RoutingHandler routingHandler, HttpString method, boolean useAuthorization, ApiHandler... handlers) {
for (ApiHandler handler : handlers) {
attachHandler(routingHandler, method, handler, useAuthorization, sane(handler));

View File

@@ -35,6 +35,7 @@ import io.kamax.mxisd.directory.DirectoryManager;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.dns.ClientDnsOverwrite;
import io.kamax.mxisd.dns.FederationDnsOverwrite;
import io.kamax.mxisd.hash.HashManager;
import io.kamax.mxisd.invitation.InvitationManager;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.lookup.fetcher.IRemoteIdentityServerFetcher;
@@ -87,6 +88,7 @@ public class Mxisd {
private NotificationManager notifMgr;
private RegistrationManager regMgr;
private AccountManager accMgr;
private HashManager hashManager;
// HS-specific classes
private Synapse synapse;
@@ -127,6 +129,9 @@ public class Mxisd {
regMgr = new RegistrationManager(cfg.getRegister(), httpClient, clientDns, invMgr);
asHander = new AppSvcManager(this);
accMgr = new AccountManager(store, resolver, getHttpClient(), cfg.getAccountConfig(), cfg.getMatrix());
hashManager = new HashManager();
hashManager.init(cfg.getHashing(), ThreePidProviders.get());
}
public MxisdConfig getConfig() {
@@ -201,6 +206,10 @@ public class Mxisd {
return accMgr;
}
public HashManager getHashManager() {
return hashManager;
}
public void start() {
build();
}

View File

@@ -0,0 +1,65 @@
package io.kamax.mxisd.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HashingConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(HashingConfig.class);
private boolean enabled = false;
private int pepperLength = 10;
private RotationPolicyEnum rotationPolicy;
private HashStorageEnum hashStorageType;
public void build() {
if (isEnabled()) {
LOGGER.info("--- Hash configuration ---");
LOGGER.info(" Pepper length: {}", getPepperLength());
LOGGER.info(" Rotation policy: {}", getRotationPolicy());
LOGGER.info(" Hash storage type: {}", getHashStorageType());
} else {
LOGGER.info("Hash configuration disabled, used only `none` pepper.");
}
}
public enum RotationPolicyEnum {
PER_REQUESTS
}
public enum HashStorageEnum {
IN_MEMORY
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public int getPepperLength() {
return pepperLength;
}
public void setPepperLength(int pepperLength) {
this.pepperLength = pepperLength;
}
public RotationPolicyEnum getRotationPolicy() {
return rotationPolicy;
}
public void setRotationPolicy(RotationPolicyEnum rotationPolicy) {
this.rotationPolicy = rotationPolicy;
}
public HashStorageEnum getHashStorageType() {
return hashStorageType;
}
public void setHashStorageType(HashStorageEnum hashStorageType) {
this.hashStorageType = hashStorageType;
}
}

View File

@@ -116,6 +116,7 @@ public class MxisdConfig {
private ViewConfig view = new ViewConfig();
private WordpressConfig wordpress = new WordpressConfig();
private PolicyConfig policy = new PolicyConfig();
private HashingConfig hashing = new HashingConfig();
public AppServiceConfig getAppsvc() {
return appsvc;
@@ -333,6 +334,14 @@ public class MxisdConfig {
this.policy = policy;
}
public HashingConfig getHashing() {
return hashing;
}
public void setHashing(HashingConfig hashing) {
this.hashing = hashing;
}
public MxisdConfig inMemory() {
getKey().setPath(":memory:");
getStorage().getProvider().getSqlite().setDatabase(":memory:");
@@ -372,6 +381,7 @@ public class MxisdConfig {
getView().build();
getWordpress().build();
getPolicy().build();
getHashing().build();
return this;
}

View File

@@ -15,8 +15,6 @@ public class PolicyConfig {
private Map<String, PolicyObject> policies = new HashMap<>();
private AcceptingPolicy acceptingPolicy = AcceptingPolicy.ANY;
public static class TermObject {
private String name;
@@ -87,14 +85,6 @@ public class PolicyConfig {
this.policies = policies;
}
public AcceptingPolicy getAcceptingPolicy() {
return acceptingPolicy;
}
public void setAcceptingPolicy(AcceptingPolicy acceptingPolicy) {
this.acceptingPolicy = acceptingPolicy;
}
public void build() {
LOGGER.info("--- Policy Config ---");
if (getPolicies().isEmpty()) {

View File

@@ -0,0 +1,50 @@
package io.kamax.mxisd.hash;
import io.kamax.matrix.codec.MxSha256;
import io.kamax.mxisd.config.HashingConfig;
import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.apache.commons.lang3.RandomStringUtils;
import java.util.List;
public class HashEngine {
private final List<? extends IThreePidProvider> providers;
private final HashStorage hashStorage;
private final MxSha256 sha256 = new MxSha256();
private final HashingConfig config;
private String pepper;
public HashEngine(List<? extends IThreePidProvider> providers, HashStorage hashStorage, HashingConfig config) {
this.providers = providers;
this.hashStorage = hashStorage;
this.config = config;
}
public void updateHashes() {
synchronized (hashStorage) {
this.pepper = newPepper();
hashStorage.clear();
for (IThreePidProvider provider : providers) {
for (ThreePidMapping pidMapping : provider.populateHashes()) {
hashStorage.add(pidMapping, hash(pidMapping));
}
}
}
}
public String getPepper() {
synchronized (hashStorage) {
return pepper;
}
}
protected String hash(ThreePidMapping pidMapping) {
return sha256.hash(pidMapping.getMedium() + " " + pidMapping.getValue() + " " + getPepper());
}
protected String newPepper() {
return RandomStringUtils.random(config.getPepperLength());
}
}

View File

@@ -0,0 +1,62 @@
package io.kamax.mxisd.hash;
import io.kamax.mxisd.config.HashingConfig;
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class HashManager {
private static final Logger LOGGER = LoggerFactory.getLogger(HashManager.class);
private HashEngine hashEngine;
private HashRotationStrategy rotationStrategy;
private HashStorage hashStorage;
private HashingConfig config;
public void init(HashingConfig config, List<? extends IThreePidProvider> providers) {
this.config = config;
initStorage();
hashEngine = new HashEngine(providers, getHashStorage(), config);
initRotationStrategy();
}
private void initStorage() {
switch (config.getHashStorageType()) {
case IN_MEMORY:
this.hashStorage = new InMemoryHashStorage();
break;
default:
throw new IllegalArgumentException("Unknown storage type: " + config.getHashStorageType());
}
}
private void initRotationStrategy() {
switch (config.getRotationPolicy()) {
case PER_REQUESTS:
this.rotationStrategy = new RotationPerRequests();
break;
default:
throw new IllegalArgumentException("Unknown rotation type: " + config.getHashStorageType());
}
this.rotationStrategy.register(getHashEngine());
}
public HashEngine getHashEngine() {
return hashEngine;
}
public HashRotationStrategy getRotationStrategy() {
return rotationStrategy;
}
public HashStorage getHashStorage() {
return hashStorage;
}
public HashingConfig getConfig() {
return config;
}
}

View File

@@ -0,0 +1,14 @@
package io.kamax.mxisd.hash;
public interface HashRotationStrategy {
void register(HashEngine hashEngine);
HashEngine getHashEngine();
void newRequest();
default void trigger() {
getHashEngine().updateHashes();
}
}

View File

@@ -0,0 +1,13 @@
package io.kamax.mxisd.hash;
import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.lookup.ThreePidMapping;
public interface HashStorage {
Iterable<ThreePidMapping> find(Iterable<String> hashes);
void add(ThreePidMapping pidMapping, String hash);
void clear();
}

View File

@@ -0,0 +1,35 @@
package io.kamax.mxisd.hash;
import io.kamax.mxisd.lookup.ThreePidMapping;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class InMemoryHashStorage implements HashStorage {
private final Map<String, ThreePidMapping> mapping = new ConcurrentHashMap<>();
@Override
public Iterable<ThreePidMapping> find(Iterable<String> hashes) {
List<ThreePidMapping> result = new ArrayList<>();
for (String hash : hashes) {
ThreePidMapping pidMapping = mapping.get(hash);
if (pidMapping != null) {
result.add(pidMapping);
}
}
return result;
}
@Override
public void add(ThreePidMapping pidMapping, String hash) {
mapping.put(hash, pidMapping);
}
@Override
public void clear() {
mapping.clear();
}
}

View File

@@ -0,0 +1,28 @@
package io.kamax.mxisd.hash;
import java.util.concurrent.atomic.AtomicInteger;
public class RotationPerRequests implements HashRotationStrategy {
private HashEngine hashEngine;
private final AtomicInteger counter = new AtomicInteger(0);
@Override
public void register(HashEngine hashEngine) {
this.hashEngine = hashEngine;
}
@Override
public HashEngine getHashEngine() {
return hashEngine;
}
@Override
public synchronized void newRequest() {
int newValue = counter.incrementAndGet();
if (newValue >= 10) {
counter.set(0);
trigger();
}
}
}

View File

@@ -0,0 +1,42 @@
package io.kamax.mxisd.http.undertow.handler.identity.v2;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.kamax.mxisd.hash.HashManager;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.undertow.server.HttpServerExchange;
public class HashDetailsHandler extends BasicHttpHandler {
public static final String PATH = "/_matrix/identity/v2/hash_details";
private final HashManager hashManager;
private volatile JsonObject response = null;
public HashDetailsHandler(HashManager hashManager) {
this.hashManager = hashManager;
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
respond(exchange, getResponse());
}
private JsonObject getResponse() {
if (response == null) {
synchronized (this) {
if (response == null) {
response = new JsonObject();
response.addProperty("lookup_pepper", hashManager.getHashEngine().getPepper());
JsonArray algorithms = new JsonArray();
algorithms.add("none");
if (hashManager.getConfig().isEnabled()) {
algorithms.add("sha256");
}
response.add("algorithms", algorithms);
}
}
}
return response;
}
}

View File

@@ -24,6 +24,7 @@ import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -40,4 +41,7 @@ public interface IThreePidProvider {
List<ThreePidMapping> populate(List<ThreePidMapping> mappings);
default Iterable<ThreePidMapping> populateHashes() {
return Collections.emptyList();
}
}