Introduce ArtController
This commit is contained in:
parent
636c8ba384
commit
9aceaa7a4d
|
@ -319,6 +319,10 @@ paymentsService:
|
||||||
# list of symbols for supported currencies
|
# list of symbols for supported currencies
|
||||||
- MOB
|
- MOB
|
||||||
|
|
||||||
|
artService:
|
||||||
|
userAuthenticationTokenSharedSecret: 0000000f0000000f0000000f0000000f0000000f0000000f0000000f0000000f # hex-encoded 32-byte secret not shared with any external service, but used in ArtController
|
||||||
|
userAuthenticationTokenUserIdSecret: 00000f # hex-encoded secret to obscure user phone numbers from Sticker Creator
|
||||||
|
|
||||||
badges:
|
badges:
|
||||||
badges:
|
badges:
|
||||||
- id: TEST
|
- id: TEST
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2021 Signal Messenger, LLC
|
* Copyright 2013 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecuregcm;
|
package org.whispersystems.textsecuregcm;
|
||||||
|
@ -33,6 +33,7 @@ import org.whispersystems.textsecuregcm.configuration.MaxDeviceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.MessageCacheConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.MessageCacheConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.OneTimeDonationConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.OneTimeDonationConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.PaymentsServiceConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.PaymentsServiceConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.ArtServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RecaptchaConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.RecaptchaConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RedisClusterConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.RedisClusterConfiguration;
|
||||||
|
@ -214,6 +215,11 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private PaymentsServiceConfiguration paymentsService;
|
private PaymentsServiceConfiguration paymentsService;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty
|
||||||
|
private ArtServiceConfiguration artService;
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@NotNull
|
@NotNull
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
|
@ -405,6 +411,10 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
return paymentsService;
|
return paymentsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArtServiceConfiguration getArtServiceConfiguration() {
|
||||||
|
return artService;
|
||||||
|
}
|
||||||
|
|
||||||
public ZkConfig getZkConfig() {
|
public ZkConfig getZkConfig() {
|
||||||
return zkConfig;
|
return zkConfig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ import org.whispersystems.textsecuregcm.controllers.RemoteConfigController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.StickerController;
|
import org.whispersystems.textsecuregcm.controllers.StickerController;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.ArtController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.SubscriptionController;
|
import org.whispersystems.textsecuregcm.controllers.SubscriptionController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.VoiceVerificationController;
|
import org.whispersystems.textsecuregcm.controllers.VoiceVerificationController;
|
||||||
import org.whispersystems.textsecuregcm.currency.CoinMarketCapClient;
|
import org.whispersystems.textsecuregcm.currency.CoinMarketCapClient;
|
||||||
|
@ -465,6 +466,10 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
config.getSecureBackupServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
config.getSecureBackupServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
||||||
ExternalServiceCredentialGenerator paymentsCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialGenerator paymentsCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
||||||
config.getPaymentsServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
config.getPaymentsServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
||||||
|
ExternalServiceCredentialGenerator artCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
||||||
|
config.getArtServiceConfiguration().getUserAuthenticationTokenSharedSecret(),
|
||||||
|
config.getArtServiceConfiguration().getUserAuthenticationTokenUserIdSecret(),
|
||||||
|
true, false, false);
|
||||||
|
|
||||||
RegistrationServiceClient registrationServiceClient = new RegistrationServiceClient(config.getRegistrationServiceConfiguration().getHost(), config.getRegistrationServiceConfiguration().getPort(), config.getRegistrationServiceConfiguration().getApiKey(), config.getRegistrationServiceConfiguration().getRegistrationCaCertificate(), registrationCallbackExecutor);
|
RegistrationServiceClient registrationServiceClient = new RegistrationServiceClient(config.getRegistrationServiceConfiguration().getHost(), config.getRegistrationServiceConfiguration().getPort(), config.getRegistrationServiceConfiguration().getApiKey(), config.getRegistrationServiceConfiguration().getRegistrationCaCertificate(), registrationCallbackExecutor);
|
||||||
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor, config.getSecureBackupServiceConfiguration());
|
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor, config.getSecureBackupServiceConfiguration());
|
||||||
|
@ -674,6 +679,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
|
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
|
||||||
|
|
||||||
final List<Object> commonControllers = Lists.newArrayList(
|
final List<Object> commonControllers = Lists.newArrayList(
|
||||||
|
new ArtController(rateLimiters, artCredentialsGenerator),
|
||||||
new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket()),
|
new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket()),
|
||||||
new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey()),
|
new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey()),
|
||||||
new CertificateController(new CertificateGenerator(config.getDeliveryCertificate().getCertificate(), config.getDeliveryCertificate().getPrivateKey(), config.getDeliveryCertificate().getExpiresDays()), zkAuthOperations, clock),
|
new CertificateController(new CertificateGenerator(config.getDeliveryCertificate().getCertificate(), config.getDeliveryCertificate().getPrivateKey(), config.getDeliveryCertificate().getExpiresDays()), zkAuthOperations, clock),
|
||||||
|
|
|
@ -9,9 +9,9 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
|
import java.util.HexFormat;
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import org.apache.commons.codec.binary.Hex;
|
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
|
|
||||||
public class ExternalServiceCredentialGenerator {
|
public class ExternalServiceCredentialGenerator {
|
||||||
|
@ -20,33 +20,50 @@ public class ExternalServiceCredentialGenerator {
|
||||||
private final byte[] userIdKey;
|
private final byte[] userIdKey;
|
||||||
private final boolean usernameDerivation;
|
private final boolean usernameDerivation;
|
||||||
private final boolean prependUsername;
|
private final boolean prependUsername;
|
||||||
|
private final boolean truncateKey;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey) {
|
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey) {
|
||||||
this(key, userIdKey, true, true);
|
this(key, userIdKey, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, boolean prependUsername) {
|
public ExternalServiceCredentialGenerator(byte[] key, boolean prependUsername) {
|
||||||
this(key, new byte[0], false, prependUsername);
|
this(key, prependUsername, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalServiceCredentialGenerator(byte[] key, boolean prependUsername, boolean truncateKey) {
|
||||||
|
this(key, new byte[0], false, prependUsername, truncateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation) {
|
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation) {
|
||||||
this(key, userIdKey, usernameDerivation, true);
|
this(key, userIdKey, usernameDerivation, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
||||||
boolean prependUsername) {
|
boolean prependUsername) {
|
||||||
this(key, userIdKey, usernameDerivation, prependUsername, Clock.systemUTC());
|
this(key, userIdKey, usernameDerivation, prependUsername, true, Clock.systemUTC());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
||||||
|
boolean prependUsername, boolean truncateKey) {
|
||||||
|
this(key, userIdKey, usernameDerivation, prependUsername, truncateKey, Clock.systemUTC());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
||||||
boolean prependUsername, Clock clock) {
|
boolean prependUsername, Clock clock) {
|
||||||
|
this(key, userIdKey, usernameDerivation, prependUsername, true, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
||||||
|
boolean prependUsername, boolean truncateKey, Clock clock) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.userIdKey = userIdKey;
|
this.userIdKey = userIdKey;
|
||||||
this.usernameDerivation = usernameDerivation;
|
this.usernameDerivation = usernameDerivation;
|
||||||
this.prependUsername = prependUsername;
|
this.prependUsername = prependUsername;
|
||||||
|
this.truncateKey = truncateKey;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,14 +72,17 @@ public class ExternalServiceCredentialGenerator {
|
||||||
String username = getUserId(identity, mac, usernameDerivation);
|
String username = getUserId(identity, mac, usernameDerivation);
|
||||||
long currentTimeSeconds = clock.millis() / 1000;
|
long currentTimeSeconds = clock.millis() / 1000;
|
||||||
String prefix = username + ":" + currentTimeSeconds;
|
String prefix = username + ":" + currentTimeSeconds;
|
||||||
String output = Hex.encodeHexString(Util.truncate(getHmac(key, prefix.getBytes(), mac), 10));
|
byte[] prefixMac = getHmac(key, prefix.getBytes(), mac);
|
||||||
|
final HexFormat hex = HexFormat.of();
|
||||||
|
String output = hex.formatHex(truncateKey ? Util.truncate(prefixMac, 10) : prefixMac);
|
||||||
String token = (prependUsername ? prefix : currentTimeSeconds) + ":" + output;
|
String token = (prependUsername ? prefix : currentTimeSeconds) + ":" + output;
|
||||||
|
|
||||||
return new ExternalServiceCredentials(username, token);
|
return new ExternalServiceCredentials(username, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUserId(String number, Mac mac, boolean usernameDerivation) {
|
private String getUserId(String number, Mac mac, boolean usernameDerivation) {
|
||||||
if (usernameDerivation) return Hex.encodeHexString(Util.truncate(getHmac(userIdKey, number.getBytes(), mac), 10));
|
final HexFormat hex = HexFormat.of();
|
||||||
|
if (usernameDerivation) return hex.formatHex(Util.truncate(getHmac(userIdKey, number.getBytes(), mac), 10));
|
||||||
else return number;
|
else return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public class ArtServiceConfiguration {
|
||||||
|
|
||||||
|
@NotEmpty
|
||||||
|
@JsonProperty
|
||||||
|
private String userAuthenticationTokenSharedSecret;
|
||||||
|
|
||||||
|
@NotEmpty
|
||||||
|
@JsonProperty
|
||||||
|
private String userAuthenticationTokenUserIdSecret;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotNull
|
||||||
|
private Duration tokenExpiration = Duration.ofDays(1);
|
||||||
|
|
||||||
|
public byte[] getUserAuthenticationTokenSharedSecret() throws DecoderException {
|
||||||
|
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getUserAuthenticationTokenUserIdSecret() throws DecoderException {
|
||||||
|
return Hex.decodeHex(userAuthenticationTokenUserIdSecret.toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Duration getTokenExpiration() {
|
||||||
|
return tokenExpiration;
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,9 @@ public class RateLimitsConfiguration {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private RateLimitConfiguration stickerPack = new RateLimitConfiguration(50, 20 / (24.0 * 60.0));
|
private RateLimitConfiguration stickerPack = new RateLimitConfiguration(50, 20 / (24.0 * 60.0));
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private RateLimitConfiguration artPack = new RateLimitConfiguration(50, 20 / (24.0 * 60.0));
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private RateLimitConfiguration usernameLookup = new RateLimitConfiguration(100, 100 / (24.0 * 60.0));
|
private RateLimitConfiguration usernameLookup = new RateLimitConfiguration(100, 100 / (24.0 * 60.0));
|
||||||
|
|
||||||
|
@ -135,6 +138,10 @@ public class RateLimitsConfiguration {
|
||||||
return stickerPack;
|
return stickerPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RateLimitConfiguration getArtPack() {
|
||||||
|
return artPack;
|
||||||
|
}
|
||||||
|
|
||||||
public RateLimitConfiguration getUsernameLookup() {
|
public RateLimitConfiguration getUsernameLookup() {
|
||||||
return usernameLookup;
|
return usernameLookup;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013-2022 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
|
||||||
|
import com.codahale.metrics.annotation.Timed;
|
||||||
|
import io.dropwizard.auth.Auth;
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
|
||||||
|
@Path("/v1/art")
|
||||||
|
public class ArtController {
|
||||||
|
private final ExternalServiceCredentialGenerator artServiceCredentialGenerator;
|
||||||
|
private final RateLimiters rateLimiters;
|
||||||
|
|
||||||
|
public ArtController(RateLimiters rateLimiters,
|
||||||
|
ExternalServiceCredentialGenerator artServiceCredentialGenerator) {
|
||||||
|
this.artServiceCredentialGenerator = artServiceCredentialGenerator;
|
||||||
|
this.rateLimiters = rateLimiters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Timed
|
||||||
|
@GET
|
||||||
|
@Path("/auth")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public ExternalServiceCredentials getAuth(@Auth AuthenticatedAccount auth)
|
||||||
|
throws RateLimitExceededException {
|
||||||
|
final UUID uuid = auth.getAccount().getUuid();
|
||||||
|
rateLimiters.getArtPackLimiter().validate(uuid);
|
||||||
|
return artServiceCredentialGenerator.generateFor(uuid.toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,8 @@ public class RateLimiters {
|
||||||
|
|
||||||
private final RateLimiter profileLimiter;
|
private final RateLimiter profileLimiter;
|
||||||
private final RateLimiter stickerPackLimiter;
|
private final RateLimiter stickerPackLimiter;
|
||||||
|
|
||||||
|
private final RateLimiter artPackLimiter;
|
||||||
private final RateLimiter usernameLookupLimiter;
|
private final RateLimiter usernameLookupLimiter;
|
||||||
private final RateLimiter usernameSetLimiter;
|
private final RateLimiter usernameSetLimiter;
|
||||||
|
|
||||||
|
@ -99,6 +101,10 @@ public class RateLimiters {
|
||||||
config.getStickerPack().getBucketSize(),
|
config.getStickerPack().getBucketSize(),
|
||||||
config.getStickerPack().getLeakRatePerMinute());
|
config.getStickerPack().getLeakRatePerMinute());
|
||||||
|
|
||||||
|
this.artPackLimiter = new RateLimiter(cacheCluster, "artPack",
|
||||||
|
config.getArtPack().getBucketSize(),
|
||||||
|
config.getArtPack().getLeakRatePerMinute());
|
||||||
|
|
||||||
this.usernameLookupLimiter = new RateLimiter(cacheCluster, "usernameLookup",
|
this.usernameLookupLimiter = new RateLimiter(cacheCluster, "usernameLookup",
|
||||||
config.getUsernameLookup().getBucketSize(),
|
config.getUsernameLookup().getBucketSize(),
|
||||||
config.getUsernameLookup().getLeakRatePerMinute());
|
config.getUsernameLookup().getLeakRatePerMinute());
|
||||||
|
@ -181,6 +187,10 @@ public class RateLimiters {
|
||||||
return stickerPackLimiter;
|
return stickerPackLimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RateLimiter getArtPackLimiter() {
|
||||||
|
return artPackLimiter;
|
||||||
|
}
|
||||||
|
|
||||||
public RateLimiter getUsernameLookupLimiter() {
|
public RateLimiter getUsernameLookupLimiter() {
|
||||||
return usernameLookupLimiter;
|
return usernameLookupLimiter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013-2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
|
import io.dropwizard.testing.junit5.DropwizardExtensionsSupport;
|
||||||
|
import io.dropwizard.testing.junit5.ResourceExtension;
|
||||||
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.ArtController;
|
||||||
|
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
|
class ArtControllerTest {
|
||||||
|
|
||||||
|
private static final ExternalServiceCredentialGenerator artCredentialGenerator = new ExternalServiceCredentialGenerator(
|
||||||
|
new byte[32], new byte[32], true, false, false);
|
||||||
|
private static final RateLimiter rateLimiter = mock(RateLimiter.class);
|
||||||
|
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||||
|
|
||||||
|
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||||
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
|
||||||
|
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
||||||
|
.setMapper(SystemMapper.getMapper())
|
||||||
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
|
.addResource(new ArtController(rateLimiters, artCredentialGenerator))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetAuthToken() {
|
||||||
|
when(rateLimiters.getArtPackLimiter()).thenReturn(rateLimiter);
|
||||||
|
|
||||||
|
ExternalServiceCredentials token =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/art/auth")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
|
.get(ExternalServiceCredentials.class);
|
||||||
|
|
||||||
|
assertThat(token.getPassword()).isNotEmpty();
|
||||||
|
assertThat(token.getUsername()).isNotEmpty();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue