Create global remote config controllable in the signal server configuration (#127)

* Add global config controller through file rather than database

* Do no permit attempting to set or delete global config entries
This commit is contained in:
Ehren Kret
2020-08-10 16:31:15 -05:00
committed by GitHub
parent b14a8ff2fd
commit b97158bf7b
5 changed files with 63 additions and 9 deletions

View File

@@ -417,7 +417,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, apnFallbackManager);
ProfileController profileController = new ProfileController(rateLimiters, accountsManager, profilesManager, usernamesManager, cdnS3Client, profileCdnPolicyGenerator, profileCdnPolicySigner, config.getCdnConfiguration().getBucket(), zkProfileOperations, isZkEnabled);
StickerController stickerController = new StickerController(rateLimiters, config.getCdnConfiguration().getAccessKey(), config.getCdnConfiguration().getAccessSecret(), config.getCdnConfiguration().getRegion(), config.getCdnConfiguration().getBucket());
RemoteConfigController remoteConfigController = new RemoteConfigController(remoteConfigsManager, config.getRemoteConfigConfiguration().getAuthorizedTokens());
RemoteConfigController remoteConfigController = new RemoteConfigController(remoteConfigsManager, config.getRemoteConfigConfiguration().getAuthorizedTokens(), config.getRemoteConfigConfiguration().getGlobalConfig());
AuthFilter<BasicCredentials, Account> accountAuthFilter = new BasicCredentialAuthFilter.Builder<Account>().setAuthenticator(accountAuthenticator).buildAuthFilter ();
AuthFilter<BasicCredentials, DisabledPermittedAccount> disabledPermittedAccountAuthFilter = new BasicCredentialAuthFilter.Builder<DisabledPermittedAccount>().setAuthenticator(disabledPermittedAccountAuthenticator).buildAuthFilter();

View File

@@ -3,8 +3,10 @@ package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class RemoteConfigConfiguration {
@@ -12,7 +14,15 @@ public class RemoteConfigConfiguration {
@NotNull
private List<String> authorizedTokens = new LinkedList<>();
@NotNull
@JsonProperty
private Map<String, String> globalConfig = new HashMap<>();
public List<String> getAuthorizedTokens() {
return authorizedTokens;
}
public Map<String, String> getGlobalConfig() {
return globalConfig;
}
}

View File

@@ -27,19 +27,23 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Path("/v1/config")
public class RemoteConfigController {
private final RemoteConfigsManager remoteConfigsManager;
private final List<String> configAuthTokens;
private final Map<String, String> globalConfig;
public RemoteConfigController(RemoteConfigsManager remoteConfigsManager, List<String> configAuthTokens) {
public RemoteConfigController(RemoteConfigsManager remoteConfigsManager, List<String> configAuthTokens, Map<String, String> globalConfig) {
this.remoteConfigsManager = remoteConfigsManager;
this.configAuthTokens = configAuthTokens;
this.configAuthTokens = configAuthTokens;
this.globalConfig = globalConfig;
}
@Timed
@@ -50,11 +54,12 @@ public class RemoteConfigController {
try {
MessageDigest digest = MessageDigest.getInstance("SHA1");
return new UserRemoteConfigList(remoteConfigsManager.getAll().stream().map(config -> {
final Stream<UserRemoteConfig> globalConfigStream = globalConfig.entrySet().stream().map(entry -> new UserRemoteConfig("g." + entry.getKey(), true, entry.getValue()));
return new UserRemoteConfigList(Stream.concat(remoteConfigsManager.getAll().stream().map(config -> {
final byte[] hashKey = config.getHashKey() != null ? config.getHashKey().getBytes(StandardCharsets.UTF_8) : config.getName().getBytes(StandardCharsets.UTF_8);
boolean inBucket = isInBucket(digest, account.getUuid(), hashKey, config.getPercentage(), config.getUuids());
return new UserRemoteConfig(config.getName(), inBucket, inBucket ? config.getValue() : config.getDefaultValue());
}).collect(Collectors.toList()));
}), globalConfigStream).collect(Collectors.toList()));
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
@@ -69,6 +74,10 @@ public class RemoteConfigController {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
if (config.getName().startsWith("g.")) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
remoteConfigsManager.set(config);
}
@@ -80,6 +89,10 @@ public class RemoteConfigController {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
if (name.startsWith("g.")) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
remoteConfigsManager.delete(name);
}