refactoring of ExternalServiceCredentialGenerator
This commit is contained in:
parent
dd98f7f043
commit
eb499833c6
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2022 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;
|
||||||
|
@ -80,16 +80,18 @@ import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
import org.whispersystems.textsecuregcm.auth.CertificateGenerator;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
||||||
import org.whispersystems.textsecuregcm.auth.WebsocketRefreshApplicationEventListener;
|
import org.whispersystems.textsecuregcm.auth.WebsocketRefreshApplicationEventListener;
|
||||||
import org.whispersystems.textsecuregcm.badges.ConfiguredProfileBadgeConverter;
|
import org.whispersystems.textsecuregcm.badges.ConfiguredProfileBadgeConverter;
|
||||||
import org.whispersystems.textsecuregcm.badges.ResourceBundleLevelTranslator;
|
import org.whispersystems.textsecuregcm.badges.ResourceBundleLevelTranslator;
|
||||||
import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
|
import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
|
||||||
import org.whispersystems.textsecuregcm.captcha.HCaptchaClient;
|
import org.whispersystems.textsecuregcm.captcha.HCaptchaClient;
|
||||||
|
import org.whispersystems.textsecuregcm.captcha.RecaptchaClient;
|
||||||
import org.whispersystems.textsecuregcm.configuration.DirectoryServerConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.DirectoryServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.ArtController;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
||||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV3;
|
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV3;
|
||||||
import org.whispersystems.textsecuregcm.controllers.CertificateController;
|
import org.whispersystems.textsecuregcm.controllers.CertificateController;
|
||||||
|
@ -108,15 +110,14 @@ 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;
|
||||||
import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager;
|
import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager;
|
||||||
import org.whispersystems.textsecuregcm.currency.FixerClient;
|
import org.whispersystems.textsecuregcm.currency.FixerClient;
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||||
import org.whispersystems.textsecuregcm.filters.RequestStatisticsFilter;
|
|
||||||
import org.whispersystems.textsecuregcm.filters.RemoteDeprecationFilter;
|
import org.whispersystems.textsecuregcm.filters.RemoteDeprecationFilter;
|
||||||
|
import org.whispersystems.textsecuregcm.filters.RequestStatisticsFilter;
|
||||||
import org.whispersystems.textsecuregcm.filters.TimestampResponseFilter;
|
import org.whispersystems.textsecuregcm.filters.TimestampResponseFilter;
|
||||||
import org.whispersystems.textsecuregcm.limits.DynamicRateLimiters;
|
import org.whispersystems.textsecuregcm.limits.DynamicRateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.limits.PushChallengeManager;
|
import org.whispersystems.textsecuregcm.limits.PushChallengeManager;
|
||||||
|
@ -158,7 +159,6 @@ import org.whispersystems.textsecuregcm.push.ProvisioningManager;
|
||||||
import org.whispersystems.textsecuregcm.push.PushLatencyManager;
|
import org.whispersystems.textsecuregcm.push.PushLatencyManager;
|
||||||
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
||||||
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
||||||
import org.whispersystems.textsecuregcm.captcha.RecaptchaClient;
|
|
||||||
import org.whispersystems.textsecuregcm.redis.ConnectionEventLogger;
|
import org.whispersystems.textsecuregcm.redis.ConnectionEventLogger;
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||||
import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool;
|
import org.whispersystems.textsecuregcm.redis.ReplicatedJedisPool;
|
||||||
|
@ -450,29 +450,23 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
config.getBraintree().supportedCurrencies(), config.getBraintree().merchantAccounts(),
|
config.getBraintree().supportedCurrencies(), config.getBraintree().merchantAccounts(),
|
||||||
config.getBraintree().graphqlUrl(), config.getBraintree().circuitBreaker(), subscriptionProcessorExecutor);
|
config.getBraintree().graphqlUrl(), config.getBraintree().circuitBreaker(), subscriptionProcessorExecutor);
|
||||||
|
|
||||||
ExternalServiceCredentialGenerator directoryCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator directoryCredentialsGenerator = DirectoryController.credentialsGenerator(
|
||||||
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenSharedSecret(),
|
config.getDirectoryConfiguration().getDirectoryClientConfiguration());
|
||||||
config.getDirectoryConfiguration().getDirectoryClientConfiguration().getUserAuthenticationTokenUserIdSecret());
|
ExternalServiceCredentialsGenerator directoryV2CredentialsGenerator = DirectoryV2Controller.credentialsGenerator(
|
||||||
ExternalServiceCredentialGenerator directoryV2CredentialsGenerator = new ExternalServiceCredentialGenerator(
|
config.getDirectoryV2Configuration().getDirectoryV2ClientConfiguration());
|
||||||
config.getDirectoryV2Configuration().getDirectoryV2ClientConfiguration().getUserAuthenticationTokenSharedSecret(),
|
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
||||||
config.getDirectoryV2Configuration().getDirectoryV2ClientConfiguration().getUserIdTokenSharedSecret(),
|
config.getSecureStorageServiceConfiguration());
|
||||||
true, false);
|
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
||||||
|
config.getSecureBackupServiceConfiguration());
|
||||||
|
ExternalServiceCredentialsGenerator paymentsCredentialsGenerator = PaymentsController.credentialsGenerator(
|
||||||
|
config.getPaymentsServiceConfiguration());
|
||||||
|
ExternalServiceCredentialsGenerator artCredentialsGenerator = ArtController.credentialsGenerator(
|
||||||
|
config.getArtServiceConfiguration());
|
||||||
|
|
||||||
dynamicConfigurationManager.start();
|
dynamicConfigurationManager.start();
|
||||||
|
|
||||||
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager);
|
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager);
|
||||||
|
|
||||||
ExternalServiceCredentialGenerator storageCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
|
||||||
config.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
|
||||||
ExternalServiceCredentialGenerator backupCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
|
||||||
config.getSecureBackupServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
|
||||||
ExternalServiceCredentialGenerator paymentsCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
|
||||||
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());
|
||||||
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator, storageServiceExecutor, config.getSecureStorageServiceConfiguration());
|
SecureStorageClient secureStorageClient = new SecureStorageClient(storageCredentialsGenerator, storageServiceExecutor, config.getSecureStorageServiceConfiguration());
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2013-2021 Signal Messenger, LLC
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.auth;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.util.HexFormat;
|
|
||||||
import javax.crypto.Mac;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
|
||||||
|
|
||||||
public class ExternalServiceCredentialGenerator {
|
|
||||||
|
|
||||||
private final byte[] key;
|
|
||||||
private final byte[] userIdKey;
|
|
||||||
private final boolean usernameDerivation;
|
|
||||||
private final boolean prependUsername;
|
|
||||||
private final boolean truncateKey;
|
|
||||||
private final Clock clock;
|
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey) {
|
|
||||||
this(key, userIdKey, true, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, boolean prependUsername) {
|
|
||||||
this(key, prependUsername, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, boolean prependUsername, boolean truncateKey) {
|
|
||||||
this(key, new byte[0], false, prependUsername, truncateKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation) {
|
|
||||||
this(key, userIdKey, usernameDerivation, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
|
||||||
boolean prependUsername) {
|
|
||||||
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
|
|
||||||
public ExternalServiceCredentialGenerator(byte[] key, byte[] userIdKey, boolean usernameDerivation,
|
|
||||||
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.userIdKey = userIdKey;
|
|
||||||
this.usernameDerivation = usernameDerivation;
|
|
||||||
this.prependUsername = prependUsername;
|
|
||||||
this.truncateKey = truncateKey;
|
|
||||||
this.clock = clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExternalServiceCredentials generateFor(String identity) {
|
|
||||||
Mac mac = getMacInstance();
|
|
||||||
String username = getUserId(identity, mac, usernameDerivation);
|
|
||||||
long currentTimeSeconds = clock.millis() / 1000;
|
|
||||||
String prefix = username + ":" + currentTimeSeconds;
|
|
||||||
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;
|
|
||||||
|
|
||||||
return new ExternalServiceCredentials(username, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getUserId(String number, Mac mac, boolean usernameDerivation) {
|
|
||||||
final HexFormat hex = HexFormat.of();
|
|
||||||
if (usernameDerivation) return hex.formatHex(Util.truncate(getHmac(userIdKey, number.getBytes(), mac), 10));
|
|
||||||
else return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Mac getMacInstance() {
|
|
||||||
try {
|
|
||||||
return Mac.getInstance("HmacSHA256");
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] getHmac(byte[] key, byte[] input, Mac mac) {
|
|
||||||
try {
|
|
||||||
mac.init(new SecretKeySpec(key, "HmacSHA256"));
|
|
||||||
return mac.doFinal(input);
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.auth;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static org.whispersystems.textsecuregcm.util.HmacUtils.hmac256ToHexString;
|
||||||
|
import static org.whispersystems.textsecuregcm.util.HmacUtils.hmac256TruncatedToHexString;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
public class ExternalServiceCredentialsGenerator {
|
||||||
|
|
||||||
|
private static final int TRUNCATE_LENGTH = 10;
|
||||||
|
|
||||||
|
private final byte[] key;
|
||||||
|
|
||||||
|
private final byte[] userDerivationKey;
|
||||||
|
|
||||||
|
private final boolean prependUsername;
|
||||||
|
|
||||||
|
private final boolean truncateSignature;
|
||||||
|
|
||||||
|
private final Clock clock;
|
||||||
|
|
||||||
|
|
||||||
|
public static ExternalServiceCredentialsGenerator.Builder builder(final byte[] key) {
|
||||||
|
return new Builder(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExternalServiceCredentialsGenerator(
|
||||||
|
final byte[] key,
|
||||||
|
final byte[] userDerivationKey,
|
||||||
|
final boolean prependUsername,
|
||||||
|
final boolean truncateSignature,
|
||||||
|
final Clock clock) {
|
||||||
|
this.key = requireNonNull(key);
|
||||||
|
this.userDerivationKey = requireNonNull(userDerivationKey);
|
||||||
|
this.prependUsername = prependUsername;
|
||||||
|
this.truncateSignature = truncateSignature;
|
||||||
|
this.clock = requireNonNull(clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalServiceCredentials generateForUuid(final UUID uuid) {
|
||||||
|
return generateFor(uuid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalServiceCredentials generateFor(final String identity) {
|
||||||
|
final String username = userDerivationKey.length > 0
|
||||||
|
? hmac256TruncatedToHexString(userDerivationKey, identity, TRUNCATE_LENGTH)
|
||||||
|
: identity;
|
||||||
|
|
||||||
|
final long currentTimeSeconds = TimeUnit.MILLISECONDS.toSeconds(clock.millis());
|
||||||
|
|
||||||
|
final String dataToSign = username + ":" + currentTimeSeconds;
|
||||||
|
|
||||||
|
final String signature = truncateSignature
|
||||||
|
? hmac256TruncatedToHexString(key, dataToSign, TRUNCATE_LENGTH)
|
||||||
|
: hmac256ToHexString(key, dataToSign);
|
||||||
|
|
||||||
|
final String token = (prependUsername ? dataToSign : currentTimeSeconds) + ":" + signature;
|
||||||
|
|
||||||
|
return new ExternalServiceCredentials(username, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private final byte[] key;
|
||||||
|
|
||||||
|
private byte[] userDerivationKey = new byte[0];
|
||||||
|
|
||||||
|
private boolean prependUsername = true;
|
||||||
|
|
||||||
|
private boolean truncateSignature = true;
|
||||||
|
|
||||||
|
private Clock clock = Clock.systemUTC();
|
||||||
|
|
||||||
|
|
||||||
|
private Builder(final byte[] key) {
|
||||||
|
this.key = requireNonNull(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withUserDerivationKey(final byte[] userDerivationKey) {
|
||||||
|
Validate.isTrue(requireNonNull(userDerivationKey).length > 0, "userDerivationKey must not be empty");
|
||||||
|
this.userDerivationKey = userDerivationKey;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withClock(final Clock clock) {
|
||||||
|
this.clock = requireNonNull(clock);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder prependUsername(final boolean prependUsername) {
|
||||||
|
this.prependUsername = prependUsername;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder truncateSignature(final boolean truncateSignature) {
|
||||||
|
this.truncateSignature = truncateSignature;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalServiceCredentialsGenerator build() {
|
||||||
|
return new ExternalServiceCredentialsGenerator(
|
||||||
|
key, userDerivationKey, prependUsername, truncateSignature, clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 Signal Messenger, LLC
|
* Copyright 2013-2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecuregcm.configuration;
|
package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import org.whispersystems.textsecuregcm.util.ExactlySize;
|
import org.whispersystems.textsecuregcm.util.ExactlySize;
|
||||||
|
|
||||||
public class DirectoryV2ClientConfiguration {
|
public record DirectoryV2ClientConfiguration(@ExactlySize({32}) byte[] userAuthenticationTokenSharedSecret,
|
||||||
|
@ExactlySize({32}) byte[] userIdTokenSharedSecret) {
|
||||||
private final byte[] userAuthenticationTokenSharedSecret;
|
|
||||||
private final byte[] userIdTokenSharedSecret;
|
|
||||||
|
|
||||||
@JsonCreator
|
|
||||||
public DirectoryV2ClientConfiguration(
|
|
||||||
@JsonProperty("userAuthenticationTokenSharedSecret") final byte[] userAuthenticationTokenSharedSecret,
|
|
||||||
@JsonProperty("userIdTokenSharedSecret") final byte[] userIdTokenSharedSecret) {
|
|
||||||
this.userAuthenticationTokenSharedSecret = userAuthenticationTokenSharedSecret;
|
|
||||||
this.userIdTokenSharedSecret = userIdTokenSharedSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExactlySize({32})
|
|
||||||
public byte[] getUserAuthenticationTokenSharedSecret() {
|
|
||||||
return userAuthenticationTokenSharedSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExactlySize({32})
|
|
||||||
public byte[] getUserIdTokenSharedSecret() {
|
|
||||||
return userIdTokenSharedSecret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 Signal Messenger, LLC
|
* Copyright 2013 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -7,65 +7,28 @@ package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import java.util.List;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import org.apache.commons.codec.DecoderException;
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.apache.commons.codec.binary.Hex;
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SecureStorageServiceConfiguration {
|
public record SecureStorageServiceConfiguration(@NotEmpty String userAuthenticationTokenSharedSecret,
|
||||||
|
@NotBlank String uri,
|
||||||
|
@NotEmpty List<@NotBlank String> storageCaCertificates,
|
||||||
|
@Valid @JsonProperty("circuitBreaker") CircuitBreakerConfiguration circuitBreakerConfig,
|
||||||
|
@Valid @JsonProperty("retry") RetryConfiguration retryConfig) {
|
||||||
|
|
||||||
@NotEmpty
|
@VisibleForTesting
|
||||||
@JsonProperty
|
public SecureStorageServiceConfiguration(
|
||||||
private String userAuthenticationTokenSharedSecret;
|
final @NotEmpty String userAuthenticationTokenSharedSecret,
|
||||||
|
final @NotBlank String uri,
|
||||||
|
final @NotEmpty List<@NotBlank String> storageCaCertificates) {
|
||||||
|
this(userAuthenticationTokenSharedSecret, uri, storageCaCertificates, new CircuitBreakerConfiguration(), new RetryConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
@NotBlank
|
public byte[] decodeUserAuthenticationTokenSharedSecret() throws DecoderException {
|
||||||
@JsonProperty
|
|
||||||
private String uri;
|
|
||||||
|
|
||||||
@NotEmpty
|
|
||||||
@JsonProperty
|
|
||||||
private List<@NotBlank String> storageCaCertificates;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Valid
|
|
||||||
@JsonProperty
|
|
||||||
private CircuitBreakerConfiguration circuitBreaker = new CircuitBreakerConfiguration();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Valid
|
|
||||||
@JsonProperty
|
|
||||||
private RetryConfiguration retry = new RetryConfiguration();
|
|
||||||
|
|
||||||
public byte[] getUserAuthenticationTokenSharedSecret() throws DecoderException {
|
|
||||||
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
|
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public void setUri(final String uri) {
|
|
||||||
this.uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUri() {
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public void setStorageCaCertificates(final List<String> certificatePem) {
|
|
||||||
this.storageCaCertificates = certificatePem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getStorageCaCertificates() {
|
|
||||||
return storageCaCertificates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CircuitBreakerConfiguration getCircuitBreakerConfiguration() {
|
|
||||||
return circuitBreaker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RetryConfiguration getRetryConfiguration() {
|
|
||||||
return retry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.controllers;
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
@ -61,8 +61,8 @@ import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
||||||
import org.whispersystems.textsecuregcm.auth.BasicAuthorizationHeader;
|
import org.whispersystems.textsecuregcm.auth.BasicAuthorizationHeader;
|
||||||
import org.whispersystems.textsecuregcm.auth.ChangesDeviceEnabledState;
|
import org.whispersystems.textsecuregcm.auth.ChangesDeviceEnabledState;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
|
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
||||||
import org.whispersystems.textsecuregcm.auth.TurnToken;
|
import org.whispersystems.textsecuregcm.auth.TurnToken;
|
||||||
|
@ -165,7 +165,7 @@ public class AccountController {
|
||||||
private final Map<String, Integer> testDevices;
|
private final Map<String, Integer> testDevices;
|
||||||
private final CaptchaChecker captchaChecker;
|
private final CaptchaChecker captchaChecker;
|
||||||
private final PushNotificationManager pushNotificationManager;
|
private final PushNotificationManager pushNotificationManager;
|
||||||
private final ExternalServiceCredentialGenerator backupServiceCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator backupServiceCredentialsGenerator;
|
||||||
|
|
||||||
private final ChangeNumberManager changeNumberManager;
|
private final ChangeNumberManager changeNumberManager;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
@ -186,7 +186,7 @@ public class AccountController {
|
||||||
CaptchaChecker captchaChecker,
|
CaptchaChecker captchaChecker,
|
||||||
PushNotificationManager pushNotificationManager,
|
PushNotificationManager pushNotificationManager,
|
||||||
ChangeNumberManager changeNumberManager,
|
ChangeNumberManager changeNumberManager,
|
||||||
ExternalServiceCredentialGenerator backupServiceCredentialGenerator,
|
ExternalServiceCredentialsGenerator backupServiceCredentialsGenerator,
|
||||||
ClientPresenceManager clientPresenceManager,
|
ClientPresenceManager clientPresenceManager,
|
||||||
Clock clock
|
Clock clock
|
||||||
) {
|
) {
|
||||||
|
@ -199,7 +199,7 @@ public class AccountController {
|
||||||
this.turnTokenGenerator = turnTokenGenerator;
|
this.turnTokenGenerator = turnTokenGenerator;
|
||||||
this.captchaChecker = captchaChecker;
|
this.captchaChecker = captchaChecker;
|
||||||
this.pushNotificationManager = pushNotificationManager;
|
this.pushNotificationManager = pushNotificationManager;
|
||||||
this.backupServiceCredentialGenerator = backupServiceCredentialGenerator;
|
this.backupServiceCredentialsGenerator = backupServiceCredentialsGenerator;
|
||||||
this.changeNumberManager = changeNumberManager;
|
this.changeNumberManager = changeNumberManager;
|
||||||
this.clientPresenceManager = clientPresenceManager;
|
this.clientPresenceManager = clientPresenceManager;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
|
@ -217,12 +217,12 @@ public class AccountController {
|
||||||
CaptchaChecker captchaChecker,
|
CaptchaChecker captchaChecker,
|
||||||
PushNotificationManager pushNotificationManager,
|
PushNotificationManager pushNotificationManager,
|
||||||
ChangeNumberManager changeNumberManager,
|
ChangeNumberManager changeNumberManager,
|
||||||
ExternalServiceCredentialGenerator backupServiceCredentialGenerator
|
ExternalServiceCredentialsGenerator backupServiceCredentialsGenerator
|
||||||
) {
|
) {
|
||||||
this(pendingAccounts, accounts, rateLimiters,
|
this(pendingAccounts, accounts, rateLimiters,
|
||||||
registrationServiceClient, dynamicConfigurationManager, turnTokenGenerator, testDevices, captchaChecker,
|
registrationServiceClient, dynamicConfigurationManager, turnTokenGenerator, testDevices, captchaChecker,
|
||||||
pushNotificationManager, changeNumberManager,
|
pushNotificationManager, changeNumberManager,
|
||||||
backupServiceCredentialGenerator, null, Clock.systemUTC());
|
backupServiceCredentialsGenerator, null, Clock.systemUTC());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed
|
@Timed
|
||||||
|
@ -832,7 +832,7 @@ public class AccountController {
|
||||||
|
|
||||||
final StoredRegistrationLock existingRegistrationLock = existingAccount.getRegistrationLock();
|
final StoredRegistrationLock existingRegistrationLock = existingAccount.getRegistrationLock();
|
||||||
final ExternalServiceCredentials existingBackupCredentials =
|
final ExternalServiceCredentials existingBackupCredentials =
|
||||||
backupServiceCredentialGenerator.generateFor(existingAccount.getUuid().toString());
|
backupServiceCredentialsGenerator.generateForUuid(existingAccount.getUuid());
|
||||||
|
|
||||||
if (existingRegistrationLock.requiresClientRegistrationLock()) {
|
if (existingRegistrationLock.requiresClientRegistrationLock()) {
|
||||||
if (!Util.isEmpty(clientRegistrationLock)) {
|
if (!Util.isEmpty(clientRegistrationLock)) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2022 Signal Messenger, LLC
|
* Copyright 2013 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -12,19 +12,34 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.ArtServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
|
||||||
@Path("/v1/art")
|
@Path("/v1/art")
|
||||||
public class ArtController {
|
public class ArtController {
|
||||||
private final ExternalServiceCredentialGenerator artServiceCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator artServiceCredentialsGenerator;
|
||||||
private final RateLimiters rateLimiters;
|
private final RateLimiters rateLimiters;
|
||||||
|
|
||||||
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final ArtServiceConfiguration cfg) {
|
||||||
|
try {
|
||||||
|
return ExternalServiceCredentialsGenerator
|
||||||
|
.builder(cfg.getUserAuthenticationTokenSharedSecret())
|
||||||
|
.withUserDerivationKey(cfg.getUserAuthenticationTokenUserIdSecret())
|
||||||
|
.prependUsername(false)
|
||||||
|
.truncateSignature(false)
|
||||||
|
.build();
|
||||||
|
} catch (DecoderException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ArtController(RateLimiters rateLimiters,
|
public ArtController(RateLimiters rateLimiters,
|
||||||
ExternalServiceCredentialGenerator artServiceCredentialGenerator) {
|
ExternalServiceCredentialsGenerator artServiceCredentialsGenerator) {
|
||||||
this.artServiceCredentialGenerator = artServiceCredentialGenerator;
|
this.artServiceCredentialsGenerator = artServiceCredentialsGenerator;
|
||||||
this.rateLimiters = rateLimiters;
|
this.rateLimiters = rateLimiters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +51,6 @@ public class ArtController {
|
||||||
throws RateLimitExceededException {
|
throws RateLimitExceededException {
|
||||||
final UUID uuid = auth.getAccount().getUuid();
|
final UUID uuid = auth.getAccount().getUuid();
|
||||||
rateLimiters.getArtPackLimiter().validate(uuid);
|
rateLimiters.getArtPackLimiter().validate(uuid);
|
||||||
return artServiceCredentialGenerator.generateFor(uuid.toString());
|
return artServiceCredentialsGenerator.generateForUuid(uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ public class AttachmentControllerV2 {
|
||||||
|
|
||||||
public AttachmentControllerV2(RateLimiters rateLimiters, String accessKey, String accessSecret, String region,
|
public AttachmentControllerV2(RateLimiters rateLimiters, String accessKey, String accessSecret, String region,
|
||||||
String bucket) {
|
String bucket) {
|
||||||
this.rateLimiter = rateLimiters.getAttachmentLimiter();
|
this.rateLimiter = rateLimiters.getAttachmentLimiter();
|
||||||
this.policyGenerator = new PostPolicyGenerator(region, bucket, accessKey);
|
this.policyGenerator = new PostPolicyGenerator(region, bucket, accessKey);
|
||||||
this.policySigner = new PolicySigner(accessSecret, region);
|
this.policySigner = new PolicySigner(accessSecret, region);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.controllers;
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
@ -13,15 +13,25 @@ import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.DirectoryClientConfiguration;
|
||||||
|
|
||||||
@Path("/v1/directory")
|
@Path("/v1/directory")
|
||||||
public class DirectoryController {
|
public class DirectoryController {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator directoryServiceTokenGenerator;
|
private final ExternalServiceCredentialsGenerator directoryServiceTokenGenerator;
|
||||||
|
|
||||||
public DirectoryController(ExternalServiceCredentialGenerator userTokenGenerator) {
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final DirectoryClientConfiguration cfg)
|
||||||
|
throws DecoderException {
|
||||||
|
return ExternalServiceCredentialsGenerator
|
||||||
|
.builder(cfg.getUserAuthenticationTokenSharedSecret())
|
||||||
|
.withUserDerivationKey(cfg.getUserAuthenticationTokenUserIdSecret())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryController(ExternalServiceCredentialsGenerator userTokenGenerator) {
|
||||||
this.directoryServiceTokenGenerator = userTokenGenerator;
|
this.directoryServiceTokenGenerator = userTokenGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* 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.controllers;
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
|
||||||
import com.codahale.metrics.annotation.Timed;
|
import com.codahale.metrics.annotation.Timed;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import io.dropwizard.auth.Auth;
|
import io.dropwizard.auth.Auth;
|
||||||
|
import java.time.Clock;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
@ -13,15 +15,31 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.DirectoryV2ClientConfiguration;
|
||||||
|
|
||||||
@Path("/v2/directory")
|
@Path("/v2/directory")
|
||||||
public class DirectoryV2Controller {
|
public class DirectoryV2Controller {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator directoryServiceTokenGenerator;
|
private final ExternalServiceCredentialsGenerator directoryServiceTokenGenerator;
|
||||||
|
|
||||||
public DirectoryV2Controller(ExternalServiceCredentialGenerator userTokenGenerator) {
|
@VisibleForTesting
|
||||||
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final DirectoryV2ClientConfiguration cfg,
|
||||||
|
final Clock clock) {
|
||||||
|
return ExternalServiceCredentialsGenerator
|
||||||
|
.builder(cfg.userAuthenticationTokenSharedSecret())
|
||||||
|
.withUserDerivationKey(cfg.userIdTokenSharedSecret())
|
||||||
|
.prependUsername(false)
|
||||||
|
.withClock(clock)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final DirectoryV2ClientConfiguration cfg) {
|
||||||
|
return credentialsGenerator(cfg, Clock.systemUTC());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryV2Controller(ExternalServiceCredentialsGenerator userTokenGenerator) {
|
||||||
this.directoryServiceTokenGenerator = userTokenGenerator;
|
this.directoryServiceTokenGenerator = userTokenGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +49,7 @@ public class DirectoryV2Controller {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response getAuthToken(@Auth AuthenticatedAccount auth) {
|
public Response getAuthToken(@Auth AuthenticatedAccount auth) {
|
||||||
final UUID uuid = auth.getAccount().getUuid();
|
final UUID uuid = auth.getAccount().getUuid();
|
||||||
final ExternalServiceCredentials credentials = directoryServiceTokenGenerator.generateFor(uuid.toString());
|
final ExternalServiceCredentials credentials = directoryServiceTokenGenerator.generateForUuid(uuid);
|
||||||
return Response.ok().entity(credentials).build();
|
return Response.ok().entity(credentials).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,36 +11,47 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.PaymentsServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager;
|
import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager;
|
||||||
import org.whispersystems.textsecuregcm.entities.CurrencyConversionEntityList;
|
import org.whispersystems.textsecuregcm.entities.CurrencyConversionEntityList;
|
||||||
|
|
||||||
@Path("/v1/payments")
|
@Path("/v1/payments")
|
||||||
public class PaymentsController {
|
public class PaymentsController {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator paymentsServiceCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator paymentsServiceCredentialsGenerator;
|
||||||
private final CurrencyConversionManager currencyManager;
|
private final CurrencyConversionManager currencyManager;
|
||||||
|
|
||||||
public PaymentsController(CurrencyConversionManager currencyManager, ExternalServiceCredentialGenerator paymentsServiceCredentialGenerator) {
|
|
||||||
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final PaymentsServiceConfiguration cfg)
|
||||||
|
throws DecoderException {
|
||||||
|
return ExternalServiceCredentialsGenerator
|
||||||
|
.builder(cfg.getUserAuthenticationTokenSharedSecret())
|
||||||
|
.prependUsername(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaymentsController(final CurrencyConversionManager currencyManager, final ExternalServiceCredentialsGenerator paymentsServiceCredentialsGenerator) {
|
||||||
this.currencyManager = currencyManager;
|
this.currencyManager = currencyManager;
|
||||||
this.paymentsServiceCredentialGenerator = paymentsServiceCredentialGenerator;
|
this.paymentsServiceCredentialsGenerator = paymentsServiceCredentialsGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed
|
@Timed
|
||||||
@GET
|
@GET
|
||||||
@Path("/auth")
|
@Path("/auth")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ExternalServiceCredentials getAuth(@Auth AuthenticatedAccount auth) {
|
public ExternalServiceCredentials getAuth(final @Auth AuthenticatedAccount auth) {
|
||||||
return paymentsServiceCredentialGenerator.generateFor(auth.getAccount().getUuid().toString());
|
return paymentsServiceCredentialsGenerator.generateForUuid(auth.getAccount().getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed
|
@Timed
|
||||||
@GET
|
@GET
|
||||||
@Path("/conversions")
|
@Path("/conversions")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public CurrencyConversionEntityList getConversions(@Auth AuthenticatedAccount auth) {
|
public CurrencyConversionEntityList getConversions(final @Auth AuthenticatedAccount auth) {
|
||||||
return currencyManager.getCurrencyConversions().orElseThrow();
|
return currencyManager.getCurrencyConversions().orElseThrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,17 +11,27 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.SecureBackupServiceConfiguration;
|
||||||
|
|
||||||
@Path("/v1/backup")
|
@Path("/v1/backup")
|
||||||
public class SecureBackupController {
|
public class SecureBackupController {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator backupServiceCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator backupServiceCredentialsGenerator;
|
||||||
|
|
||||||
public SecureBackupController(ExternalServiceCredentialGenerator backupServiceCredentialGenerator) {
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final SecureBackupServiceConfiguration cfg)
|
||||||
this.backupServiceCredentialGenerator = backupServiceCredentialGenerator;
|
throws DecoderException {
|
||||||
|
return ExternalServiceCredentialsGenerator
|
||||||
|
.builder(cfg.getUserAuthenticationTokenSharedSecret())
|
||||||
|
.prependUsername(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureBackupController(ExternalServiceCredentialsGenerator backupServiceCredentialsGenerator) {
|
||||||
|
this.backupServiceCredentialsGenerator = backupServiceCredentialsGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed
|
@Timed
|
||||||
|
@ -29,6 +39,6 @@ public class SecureBackupController {
|
||||||
@Path("/auth")
|
@Path("/auth")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ExternalServiceCredentials getAuth(@Auth AuthenticatedAccount auth) {
|
public ExternalServiceCredentials getAuth(@Auth AuthenticatedAccount auth) {
|
||||||
return backupServiceCredentialGenerator.generateFor(auth.getAccount().getUuid().toString());
|
return backupServiceCredentialsGenerator.generateForUuid(auth.getAccount().getUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,17 +11,30 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
||||||
|
|
||||||
@Path("/v1/storage")
|
@Path("/v1/storage")
|
||||||
public class SecureStorageController {
|
public class SecureStorageController {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator storageServiceCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator storageServiceCredentialsGenerator;
|
||||||
|
|
||||||
public SecureStorageController(ExternalServiceCredentialGenerator storageServiceCredentialGenerator) {
|
public static ExternalServiceCredentialsGenerator credentialsGenerator(final SecureStorageServiceConfiguration cfg) {
|
||||||
this.storageServiceCredentialGenerator = storageServiceCredentialGenerator;
|
try {
|
||||||
|
return ExternalServiceCredentialsGenerator
|
||||||
|
.builder(cfg.decodeUserAuthenticationTokenSharedSecret())
|
||||||
|
.prependUsername(true)
|
||||||
|
.build();
|
||||||
|
} catch (DecoderException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecureStorageController(ExternalServiceCredentialsGenerator storageServiceCredentialsGenerator) {
|
||||||
|
this.storageServiceCredentialsGenerator = storageServiceCredentialsGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed
|
@Timed
|
||||||
|
@ -29,6 +42,6 @@ public class SecureStorageController {
|
||||||
@Path("/auth")
|
@Path("/auth")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ExternalServiceCredentials getAuth(@Auth AuthenticatedAccount auth) {
|
public ExternalServiceCredentials getAuth(@Auth AuthenticatedAccount auth) {
|
||||||
return storageServiceCredentialGenerator.generateFor(auth.getAccount().getUuid().toString());
|
return storageServiceCredentialsGenerator.generateForUuid(auth.getAccount().getUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,43 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2021 Signal Messenger, LLC
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.securebackup;
|
package org.whispersystems.textsecuregcm.securebackup;
|
||||||
|
|
||||||
|
import static org.whispersystems.textsecuregcm.util.HeaderUtils.basicAuthHeader;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.net.HttpHeaders;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.configuration.SecureBackupServiceConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.SecureBackupServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
|
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
|
||||||
|
import org.whispersystems.textsecuregcm.util.HttpUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client for sending requests to Signal's secure value recovery service on behalf of authenticated users.
|
* A client for sending requests to Signal's secure value recovery service on behalf of authenticated users.
|
||||||
*/
|
*/
|
||||||
public class SecureBackupClient {
|
public class SecureBackupClient {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator secureBackupCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator secureBackupCredentialsGenerator;
|
||||||
private final URI deleteUri;
|
private final URI deleteUri;
|
||||||
private final FaultTolerantHttpClient httpClient;
|
private final FaultTolerantHttpClient httpClient;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String DELETE_PATH = "/v1/backup";
|
static final String DELETE_PATH = "/v1/backup";
|
||||||
|
|
||||||
public SecureBackupClient(final ExternalServiceCredentialGenerator secureBackupCredentialGenerator, final Executor executor, final SecureBackupServiceConfiguration configuration) throws CertificateException {
|
public SecureBackupClient(final ExternalServiceCredentialsGenerator secureBackupCredentialsGenerator, final Executor executor, final SecureBackupServiceConfiguration configuration) throws CertificateException {
|
||||||
this.secureBackupCredentialGenerator = secureBackupCredentialGenerator;
|
this.secureBackupCredentialsGenerator = secureBackupCredentialsGenerator;
|
||||||
this.deleteUri = URI.create(configuration.getUri()).resolve(DELETE_PATH);
|
this.deleteUri = URI.create(configuration.getUri()).resolve(DELETE_PATH);
|
||||||
this.httpClient = FaultTolerantHttpClient.newBuilder()
|
this.httpClient = FaultTolerantHttpClient.newBuilder()
|
||||||
.withCircuitBreaker(configuration.getCircuitBreakerConfiguration())
|
.withCircuitBreaker(configuration.getCircuitBreakerConfiguration())
|
||||||
|
@ -51,17 +53,16 @@ public class SecureBackupClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Void> deleteBackups(final UUID accountUuid) {
|
public CompletableFuture<Void> deleteBackups(final UUID accountUuid) {
|
||||||
final ExternalServiceCredentials credentials = secureBackupCredentialGenerator.generateFor(accountUuid.toString());
|
final ExternalServiceCredentials credentials = secureBackupCredentialsGenerator.generateForUuid(accountUuid);
|
||||||
|
|
||||||
final HttpRequest request = HttpRequest.newBuilder()
|
final HttpRequest request = HttpRequest.newBuilder()
|
||||||
.uri(deleteUri)
|
.uri(deleteUri)
|
||||||
.DELETE()
|
.DELETE()
|
||||||
.header("Authorization", "Basic " + Base64.getEncoder().encodeToString(
|
.header(HttpHeaders.AUTHORIZATION, basicAuthHeader(credentials))
|
||||||
(credentials.username() + ":" + credentials.password()).getBytes(StandardCharsets.UTF_8)))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(response -> {
|
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(response -> {
|
||||||
if (response.statusCode() >= 200 && response.statusCode() < 300) {
|
if (HttpUtils.isSuccessfulResponse(response.statusCode())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,68 +1,68 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 Signal Messenger, LLC
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.securestorage;
|
package org.whispersystems.textsecuregcm.securestorage;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import static org.whispersystems.textsecuregcm.util.HeaderUtils.basicAuthHeader;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
|
||||||
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
|
||||||
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
|
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.net.HttpHeaders;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
|
||||||
|
import org.whispersystems.textsecuregcm.util.HttpUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client for sending requests to Signal's secure storage service on behalf of authenticated users.
|
* A client for sending requests to Signal's secure storage service on behalf of authenticated users.
|
||||||
*/
|
*/
|
||||||
public class SecureStorageClient {
|
public class SecureStorageClient {
|
||||||
|
|
||||||
private final ExternalServiceCredentialGenerator storageServiceCredentialGenerator;
|
private final ExternalServiceCredentialsGenerator storageServiceCredentialsGenerator;
|
||||||
private final URI deleteUri;
|
private final URI deleteUri;
|
||||||
private final FaultTolerantHttpClient httpClient;
|
private final FaultTolerantHttpClient httpClient;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String DELETE_PATH = "/v1/storage";
|
static final String DELETE_PATH = "/v1/storage";
|
||||||
|
|
||||||
public SecureStorageClient(final ExternalServiceCredentialGenerator storageServiceCredentialGenerator, final Executor executor, final SecureStorageServiceConfiguration configuration) throws CertificateException {
|
public SecureStorageClient(final ExternalServiceCredentialsGenerator storageServiceCredentialsGenerator, final Executor executor, final SecureStorageServiceConfiguration configuration) throws CertificateException {
|
||||||
this.storageServiceCredentialGenerator = storageServiceCredentialGenerator;
|
this.storageServiceCredentialsGenerator = storageServiceCredentialsGenerator;
|
||||||
this.deleteUri = URI.create(configuration.getUri()).resolve(DELETE_PATH);
|
this.deleteUri = URI.create(configuration.uri()).resolve(DELETE_PATH);
|
||||||
this.httpClient = FaultTolerantHttpClient.newBuilder()
|
this.httpClient = FaultTolerantHttpClient.newBuilder()
|
||||||
.withCircuitBreaker(configuration.getCircuitBreakerConfiguration())
|
.withCircuitBreaker(configuration.circuitBreakerConfig())
|
||||||
.withRetry(configuration.getRetryConfiguration())
|
.withRetry(configuration.retryConfig())
|
||||||
.withVersion(HttpClient.Version.HTTP_1_1)
|
.withVersion(HttpClient.Version.HTTP_1_1)
|
||||||
.withConnectTimeout(Duration.ofSeconds(10))
|
.withConnectTimeout(Duration.ofSeconds(10))
|
||||||
.withRedirect(HttpClient.Redirect.NEVER)
|
.withRedirect(HttpClient.Redirect.NEVER)
|
||||||
.withExecutor(executor)
|
.withExecutor(executor)
|
||||||
.withName("secure-storage")
|
.withName("secure-storage")
|
||||||
.withSecurityProtocol(FaultTolerantHttpClient.SECURITY_PROTOCOL_TLS_1_3)
|
.withSecurityProtocol(FaultTolerantHttpClient.SECURITY_PROTOCOL_TLS_1_3)
|
||||||
.withTrustedServerCertificates(configuration.getStorageCaCertificates().toArray(new String[0]))
|
.withTrustedServerCertificates(configuration.storageCaCertificates().toArray(new String[0]))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Void> deleteStoredData(final UUID accountUuid) {
|
public CompletableFuture<Void> deleteStoredData(final UUID accountUuid) {
|
||||||
final ExternalServiceCredentials credentials = storageServiceCredentialGenerator.generateFor(accountUuid.toString());
|
final ExternalServiceCredentials credentials = storageServiceCredentialsGenerator.generateForUuid(accountUuid);
|
||||||
|
|
||||||
final HttpRequest request = HttpRequest.newBuilder()
|
final HttpRequest request = HttpRequest.newBuilder()
|
||||||
.uri(deleteUri)
|
.uri(deleteUri)
|
||||||
.DELETE()
|
.DELETE()
|
||||||
.header("Authorization", "Basic " + Base64.getEncoder().encodeToString(
|
.header(HttpHeaders.AUTHORIZATION, basicAuthHeader(credentials))
|
||||||
(credentials.username() + ":" + credentials.password()).getBytes(StandardCharsets.UTF_8)))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(response -> {
|
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(response -> {
|
||||||
if (response.statusCode() >= 200 && response.statusCode() < 300) {
|
if (HttpUtils.isSuccessfulResponse(response.statusCode())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2022 Signal Messenger, LLC
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.whispersystems.textsecuregcm.util;
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
|
||||||
public final class HeaderUtils {
|
public final class HeaderUtils {
|
||||||
|
|
||||||
|
@ -22,6 +27,16 @@ public final class HeaderUtils {
|
||||||
// utility class
|
// utility class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String basicAuthHeader(final ExternalServiceCredentials credentials) {
|
||||||
|
return basicAuthHeader(credentials.username(), credentials.password());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String basicAuthHeader(final String username, final String password) {
|
||||||
|
requireNonNull(username);
|
||||||
|
requireNonNull(password);
|
||||||
|
return "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static String getTimestampHeader() {
|
public static String getTimestampHeader() {
|
||||||
return TIMESTAMP_HEADER + ":" + System.currentTimeMillis();
|
return TIMESTAMP_HEADER + ":" + System.currentTimeMillis();
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.HexFormat;
|
||||||
|
|
||||||
|
public final class HmacUtils {
|
||||||
|
|
||||||
|
private static final HexFormat HEX = HexFormat.of();
|
||||||
|
|
||||||
|
private static final String HMAC_SHA_256 = "HmacSHA256";
|
||||||
|
|
||||||
|
private static final ThreadLocal<Mac> THREAD_LOCAL_HMAC_SHA_256 = ThreadLocal.withInitial(() -> {
|
||||||
|
try {
|
||||||
|
return Mac.getInstance(HMAC_SHA_256);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
public static byte[] hmac256(final byte[] key, final byte[] input) {
|
||||||
|
try {
|
||||||
|
final Mac mac = THREAD_LOCAL_HMAC_SHA_256.get();
|
||||||
|
mac.init(new SecretKeySpec(key, HMAC_SHA_256));
|
||||||
|
return mac.doFinal(input);
|
||||||
|
} catch (final InvalidKeyException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] hmac256(final byte[] key, final String input) {
|
||||||
|
return hmac256(key, input.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String hmac256ToHexString(final byte[] key, final byte[] input) {
|
||||||
|
return HEX.formatHex(hmac256(key, input));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String hmac256ToHexString(final byte[] key, final String input) {
|
||||||
|
return hmac256ToHexString(key, input.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] hmac256Truncated(final byte[] key, final byte[] input, final int length) {
|
||||||
|
return Util.truncate(hmac256(key, input), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] hmac256Truncated(final byte[] key, final String input, final int length) {
|
||||||
|
return hmac256Truncated(key, input.getBytes(StandardCharsets.UTF_8), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String hmac256TruncatedToHexString(final byte[] key, final byte[] input, final int length) {
|
||||||
|
return HEX.formatHex(Util.truncate(hmac256(key, input), length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String hmac256TruncatedToHexString(final byte[] key, final String input, final int length) {
|
||||||
|
return hmac256TruncatedToHexString(key, input.getBytes(StandardCharsets.UTF_8), length);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
public final class HttpUtils {
|
||||||
|
|
||||||
|
private HttpUtils() {
|
||||||
|
// utility class
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSuccessfulResponse(final int statusCode) {
|
||||||
|
return statusCode >= 200 && statusCode < 300;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -23,8 +23,10 @@ import java.util.concurrent.Executors;
|
||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
import net.sourceforge.argparse4j.inf.Subparser;
|
import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||||
|
@ -103,11 +105,11 @@ public class AssignUsernameCommand extends EnvironmentCommand<WhisperServerConfi
|
||||||
ExecutorService storageServiceExecutor = environment.lifecycle()
|
ExecutorService storageServiceExecutor = environment.lifecycle()
|
||||||
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
||||||
|
|
||||||
ExternalServiceCredentialGenerator backupCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
||||||
configuration.getSecureBackupServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
configuration.getSecureBackupServiceConfiguration());
|
||||||
ExternalServiceCredentialGenerator storageCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
||||||
configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
configuration.getSecureStorageServiceConfiguration());
|
||||||
|
|
||||||
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
||||||
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
||||||
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -25,8 +25,10 @@ import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||||
|
@ -105,11 +107,11 @@ public class DeleteUserCommand extends EnvironmentCommand<WhisperServerConfigura
|
||||||
ExecutorService storageServiceExecutor = environment.lifecycle()
|
ExecutorService storageServiceExecutor = environment.lifecycle()
|
||||||
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
||||||
|
|
||||||
ExternalServiceCredentialGenerator backupCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
||||||
configuration.getSecureBackupServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
configuration.getSecureBackupServiceConfiguration());
|
||||||
ExternalServiceCredentialGenerator storageCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
||||||
configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
configuration.getSecureStorageServiceConfiguration());
|
||||||
|
|
||||||
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
||||||
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
||||||
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -24,8 +24,10 @@ import java.util.concurrent.Executors;
|
||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
import net.sourceforge.argparse4j.inf.Subparser;
|
import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureBackupController;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||||
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
||||||
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
|
||||||
|
@ -108,11 +110,11 @@ public class SetUserDiscoverabilityCommand extends EnvironmentCommand<WhisperSer
|
||||||
ExecutorService storageServiceExecutor = environment.lifecycle()
|
ExecutorService storageServiceExecutor = environment.lifecycle()
|
||||||
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
.executorService(name(getClass(), "storageService-%d")).maxThreads(8).minThreads(1).build();
|
||||||
|
|
||||||
ExternalServiceCredentialGenerator backupCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator backupCredentialsGenerator = SecureBackupController.credentialsGenerator(
|
||||||
configuration.getSecureBackupServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
configuration.getSecureBackupServiceConfiguration());
|
||||||
ExternalServiceCredentialGenerator storageCredentialsGenerator = new ExternalServiceCredentialGenerator(
|
ExternalServiceCredentialsGenerator storageCredentialsGenerator = SecureStorageController.credentialsGenerator(
|
||||||
configuration.getSecureStorageServiceConfiguration().getUserAuthenticationTokenSharedSecret(), true);
|
configuration.getSecureStorageServiceConfiguration());
|
||||||
|
|
||||||
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager = new DynamicConfigurationManager<>(
|
||||||
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
configuration.getAppConfig().getApplication(), configuration.getAppConfig().getEnvironment(),
|
||||||
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
configuration.getAppConfig().getConfigurationName(), DynamicConfiguration.class);
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -65,12 +65,13 @@ import org.mockito.stubbing.Answer;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
|
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
|
||||||
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
||||||
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
|
||||||
import org.whispersystems.textsecuregcm.captcha.AssessmentResult;
|
import org.whispersystems.textsecuregcm.captcha.AssessmentResult;
|
||||||
import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
|
import org.whispersystems.textsecuregcm.captcha.CaptchaChecker;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicCaptchaConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicCaptchaConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
|
||||||
|
@ -111,6 +112,7 @@ import org.whispersystems.textsecuregcm.storage.UsernameReservationNotFoundExcep
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.Hex;
|
import org.whispersystems.textsecuregcm.util.Hex;
|
||||||
|
import org.whispersystems.textsecuregcm.util.MockHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
|
||||||
|
@ -169,7 +171,13 @@ class AccountControllerTest {
|
||||||
private static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
private static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||||
|
|
||||||
private byte[] registration_lock_key = new byte[32];
|
private byte[] registration_lock_key = new byte[32];
|
||||||
private static ExternalServiceCredentialGenerator storageCredentialGenerator = new ExternalServiceCredentialGenerator(new byte[32], new byte[32], false);
|
|
||||||
|
private static final SecureStorageServiceConfiguration STORAGE_CFG = MockHelper.buildMock(
|
||||||
|
SecureStorageServiceConfiguration.class,
|
||||||
|
cfg -> when(cfg.decodeUserAuthenticationTokenSharedSecret()).thenReturn(new byte[32]));
|
||||||
|
|
||||||
|
private static final ExternalServiceCredentialsGenerator STORAGE_CREDENTIAL_GENERATOR = SecureStorageController
|
||||||
|
.credentialsGenerator(STORAGE_CFG);
|
||||||
|
|
||||||
private static final ResourceExtension resources = ResourceExtension.builder()
|
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
|
@ -192,7 +200,7 @@ class AccountControllerTest {
|
||||||
captchaChecker,
|
captchaChecker,
|
||||||
pushNotificationManager,
|
pushNotificationManager,
|
||||||
changeNumberManager,
|
changeNumberManager,
|
||||||
storageCredentialGenerator,
|
STORAGE_CREDENTIAL_GENERATOR,
|
||||||
clientPresenceManager,
|
clientPresenceManager,
|
||||||
testClock))
|
testClock))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 Signal Messenger, LLC
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -23,18 +23,18 @@ import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.configuration.SecureBackupServiceConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.SecureBackupServiceConfiguration;
|
||||||
|
|
||||||
class SecureBackupClientTest {
|
class SecureBackupClientTest {
|
||||||
|
|
||||||
private UUID accountUuid;
|
private UUID accountUuid;
|
||||||
private ExternalServiceCredentialGenerator credentialGenerator;
|
private ExternalServiceCredentialsGenerator credentialsGenerator;
|
||||||
private ExecutorService httpExecutor;
|
private ExecutorService httpExecutor;
|
||||||
|
|
||||||
private SecureBackupClient secureStorageClient;
|
private SecureBackupClient secureStorageClient;
|
||||||
|
@ -47,7 +47,7 @@ class SecureBackupClientTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws CertificateException {
|
void setUp() throws CertificateException {
|
||||||
accountUuid = UUID.randomUUID();
|
accountUuid = UUID.randomUUID();
|
||||||
credentialGenerator = mock(ExternalServiceCredentialGenerator.class);
|
credentialsGenerator = mock(ExternalServiceCredentialsGenerator.class);
|
||||||
httpExecutor = Executors.newSingleThreadExecutor();
|
httpExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
final SecureBackupServiceConfiguration config = new SecureBackupServiceConfiguration();
|
final SecureBackupServiceConfiguration config = new SecureBackupServiceConfiguration();
|
||||||
|
@ -101,7 +101,7 @@ class SecureBackupClientTest {
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
"""));
|
"""));
|
||||||
|
|
||||||
secureStorageClient = new SecureBackupClient(credentialGenerator, httpExecutor, config);
|
secureStorageClient = new SecureBackupClient(credentialsGenerator, httpExecutor, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -115,7 +115,7 @@ class SecureBackupClientTest {
|
||||||
final String username = RandomStringUtils.randomAlphabetic(16);
|
final String username = RandomStringUtils.randomAlphabetic(16);
|
||||||
final String password = RandomStringUtils.randomAlphanumeric(32);
|
final String password = RandomStringUtils.randomAlphanumeric(32);
|
||||||
|
|
||||||
when(credentialGenerator.generateFor(accountUuid.toString())).thenReturn(new ExternalServiceCredentials(username, password));
|
when(credentialsGenerator.generateForUuid(accountUuid)).thenReturn(new ExternalServiceCredentials(username, password));
|
||||||
|
|
||||||
wireMock.stubFor(delete(urlEqualTo(SecureBackupClient.DELETE_PATH))
|
wireMock.stubFor(delete(urlEqualTo(SecureBackupClient.DELETE_PATH))
|
||||||
.withBasicAuth(username, password)
|
.withBasicAuth(username, password)
|
||||||
|
@ -130,7 +130,7 @@ class SecureBackupClientTest {
|
||||||
final String username = RandomStringUtils.randomAlphabetic(16);
|
final String username = RandomStringUtils.randomAlphabetic(16);
|
||||||
final String password = RandomStringUtils.randomAlphanumeric(32);
|
final String password = RandomStringUtils.randomAlphanumeric(32);
|
||||||
|
|
||||||
when(credentialGenerator.generateFor(accountUuid.toString())).thenReturn(new ExternalServiceCredentials(username, password));
|
when(credentialsGenerator.generateForUuid(accountUuid)).thenReturn(new ExternalServiceCredentials(username, password));
|
||||||
|
|
||||||
wireMock.stubFor(delete(urlEqualTo(SecureBackupClient.DELETE_PATH))
|
wireMock.stubFor(delete(urlEqualTo(SecureBackupClient.DELETE_PATH))
|
||||||
.withBasicAuth(username, password)
|
.withBasicAuth(username, password)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 Signal Messenger, LLC
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -27,14 +27,14 @@ import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
||||||
|
|
||||||
class SecureStorageClientTest {
|
class SecureStorageClientTest {
|
||||||
|
|
||||||
private UUID accountUuid;
|
private UUID accountUuid;
|
||||||
private ExternalServiceCredentialGenerator credentialGenerator;
|
private ExternalServiceCredentialsGenerator credentialsGenerator;
|
||||||
private ExecutorService httpExecutor;
|
private ExecutorService httpExecutor;
|
||||||
|
|
||||||
private SecureStorageClient secureStorageClient;
|
private SecureStorageClient secureStorageClient;
|
||||||
|
@ -47,61 +47,60 @@ class SecureStorageClientTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws CertificateException {
|
void setUp() throws CertificateException {
|
||||||
accountUuid = UUID.randomUUID();
|
accountUuid = UUID.randomUUID();
|
||||||
credentialGenerator = mock(ExternalServiceCredentialGenerator.class);
|
credentialsGenerator = mock(ExternalServiceCredentialsGenerator.class);
|
||||||
httpExecutor = Executors.newSingleThreadExecutor();
|
httpExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
final SecureStorageServiceConfiguration config = new SecureStorageServiceConfiguration();
|
final SecureStorageServiceConfiguration config = new SecureStorageServiceConfiguration(
|
||||||
config.setUri("http://localhost:" + wireMock.getPort());
|
"not_used",
|
||||||
|
"http://localhost:" + wireMock.getPort(),
|
||||||
|
List.of("""
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICZDCCAc2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBPMQswCQYDVQQGEwJ1czEL
|
||||||
|
MAkGA1UECAwCVVMxHjAcBgNVBAoMFVNpZ25hbCBNZXNzZW5nZXIsIExMQzETMBEG
|
||||||
|
A1UEAwwKc2lnbmFsLm9yZzAeFw0yMDEyMjMyMjQ3NTlaFw0zMDEyMjEyMjQ3NTla
|
||||||
|
ME8xCzAJBgNVBAYTAnVzMQswCQYDVQQIDAJVUzEeMBwGA1UECgwVU2lnbmFsIE1l
|
||||||
|
c3NlbmdlciwgTExDMRMwEQYDVQQDDApzaWduYWwub3JnMIGfMA0GCSqGSIb3DQEB
|
||||||
|
AQUAA4GNADCBiQKBgQCfSLcZNHYqbxSsgWp4JvbPRHjQTrlsrKrgD2q7f/OY6O3Y
|
||||||
|
/X0QNcNSOJpliN8rmzwslfsrXHO3q1diGRw4xHogUJZ/7NQrHiP/zhN0VTDh49pD
|
||||||
|
ZpjXVyUbayLS/6qM5arKxBspzEFBb5v8cF6bPr76SO/rpGXiI0j6yJKX6fRiKwID
|
||||||
|
AQABo1AwTjAdBgNVHQ4EFgQU6Jrs/Fmj0z4dA3wvdq/WqA4P49IwHwYDVR0jBBgw
|
||||||
|
FoAU6Jrs/Fmj0z4dA3wvdq/WqA4P49IwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
|
||||||
|
AQ0FAAOBgQB+5d5+NtzLILfrc9QmJdIO1YeDP64JmFwTER0kEUouRsb9UwknVWZa
|
||||||
|
y7MTM4NoBV1k0zb5LAk89SIDPr/maW5AsLtEomzjnEiomjoMBUdNe3YCgQReoLnr
|
||||||
|
R/QaUNbrCjTGYfBsjGbIzmkWPUyTec2ZdRyJ8JiVl386+6CZkxnndQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEpDCCAowCCQC43PUTWSADVjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
||||||
|
b2NhbGhvc3QwHhcNMjIxMDE3MjA0NTM0WhcNMjMxMDE3MjA0NTM0WjAUMRIwEAYD
|
||||||
|
VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDV
|
||||||
|
x1cdEd2ffQTlTXWRiCHGcrlYf4RJnctt9sw/BuHWTLXBu5LhyJSGn5LRszO/NCXK
|
||||||
|
Z/cmGR7pLj366RtiwL+Qo3nhvDCK7T9xZeNIusM6XMcMK9D/DGCYPqtjQz8NXd9V
|
||||||
|
ajBBe6nwTDTa+oqX8Mt89foWNkg5Il/lY62u9Dr18LRZ2W9zzYi3Q9/K0CbIX6pM
|
||||||
|
yVlPIO5rITOR2IsbeyqsO9jufgX5lP4ZKLLBAP1b7usjC4YdvWacjQg/rK5aay1x
|
||||||
|
jC2HCDgo/4N30QVXzSA9nFfSe6AE/xkStK4819JqOkY5JsJCbef1P3hOOdSLEjbp
|
||||||
|
xq3MjOs6G6dOgteaAGs10vx7dHxDWETTIiD7BIZ9zRYgOF5bkCaIUO+JfySE1MHD
|
||||||
|
KBAFLoRuvmRev5Ln5R0MCHpUMSmMNgJqz+RWZV3g/gpYbuWiHgJOwL1393eK50Bg
|
||||||
|
W7SXQ8EjJj2yXZSH+1gPzN0DRoJZiaBoTPnCL2qUgvwFpW1PJsM5FDyUJFUoK5kK
|
||||||
|
HLBBSKAPt6ZlSrUe2nBgJv7EF1GK+fTU08LXgW33OpLceGPa0zTShkukQUMtUtZ8
|
||||||
|
GqhO12ohMzEupIu5Xurthq4VVUrzHUdj1ZZRMhAbfLU36sd03MMyL/xBqTN6dzCa
|
||||||
|
GDGIPGpYjAllZ5xMRt2kZdv+Kr6oo3u2nLUIsqI7KQIDAQABMA0GCSqGSIb3DQEB
|
||||||
|
CwUAA4ICAQCB5s43YF35ssf5YONW5iAaifGpi1o0866xfeOybtohFGvQ7V2W34i9
|
||||||
|
TYBCt8+0hgatMcvZ08f0vqig1i7nrvYcE1hnhL7JNkU8qm0s9ytHZt6j62nB0kd/
|
||||||
|
uqE2hOEQalTf/2TGPV0CCgiqLyd8lEUQvQeA38wktwUeZpVnErlzHeMR2CvV3K8R
|
||||||
|
u4vV6SnBcf+TAt56RKYZkPyvZj5llQPo14Glyoo8qZES7Ky1SHmM0GL+baPRBjRW
|
||||||
|
3KgSt98Wyu4yr9qu21JpnbAnLhBfzfSKjSeCRgFElUE1GIaFGRZ7ypA74dUKeLnb
|
||||||
|
/VUWrszmUhGaEjV9dpI6x6B/kSpQMtIQqBaKRY2ALUeEujS/rURi4iMDwSU+GkSH
|
||||||
|
cyEvZKS97OA/dWeXfLXdo4beDBRG93bI4rQnDg5+VdlBOkQSLueb8x6/VThMoC5d
|
||||||
|
vZiotFQHseljQAdTkNa6tBu6c4XDYPCKB3CfkMYOlCfTS7Acn5G6dxTPKBtLGBnL
|
||||||
|
nQfYyzuwYkN09+2PVzt6auBHr3To7uoclkxX+hxyvPIwIZ0N6b4tQR1FCAkvg29Q
|
||||||
|
WIOjZOKGW690ESKCKOnFjUHVO0HpuWnT81URTuY62FXsYdVc2wE4v0E04mEbqQ0P
|
||||||
|
lY6ZKNA81Lm3YADYtObmK1IUrOPo9BeIaPy0UM08SmN880Vunqa91Q==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
"""));
|
||||||
|
|
||||||
// This is a randomly-generated, throwaway certificate that's not actually connected to anything
|
secureStorageClient = new SecureStorageClient(credentialsGenerator, httpExecutor, config);
|
||||||
config.setStorageCaCertificates(List.of("""
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIICZDCCAc2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBPMQswCQYDVQQGEwJ1czEL
|
|
||||||
MAkGA1UECAwCVVMxHjAcBgNVBAoMFVNpZ25hbCBNZXNzZW5nZXIsIExMQzETMBEG
|
|
||||||
A1UEAwwKc2lnbmFsLm9yZzAeFw0yMDEyMjMyMjQ3NTlaFw0zMDEyMjEyMjQ3NTla
|
|
||||||
ME8xCzAJBgNVBAYTAnVzMQswCQYDVQQIDAJVUzEeMBwGA1UECgwVU2lnbmFsIE1l
|
|
||||||
c3NlbmdlciwgTExDMRMwEQYDVQQDDApzaWduYWwub3JnMIGfMA0GCSqGSIb3DQEB
|
|
||||||
AQUAA4GNADCBiQKBgQCfSLcZNHYqbxSsgWp4JvbPRHjQTrlsrKrgD2q7f/OY6O3Y
|
|
||||||
/X0QNcNSOJpliN8rmzwslfsrXHO3q1diGRw4xHogUJZ/7NQrHiP/zhN0VTDh49pD
|
|
||||||
ZpjXVyUbayLS/6qM5arKxBspzEFBb5v8cF6bPr76SO/rpGXiI0j6yJKX6fRiKwID
|
|
||||||
AQABo1AwTjAdBgNVHQ4EFgQU6Jrs/Fmj0z4dA3wvdq/WqA4P49IwHwYDVR0jBBgw
|
|
||||||
FoAU6Jrs/Fmj0z4dA3wvdq/WqA4P49IwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
|
|
||||||
AQ0FAAOBgQB+5d5+NtzLILfrc9QmJdIO1YeDP64JmFwTER0kEUouRsb9UwknVWZa
|
|
||||||
y7MTM4NoBV1k0zb5LAk89SIDPr/maW5AsLtEomzjnEiomjoMBUdNe3YCgQReoLnr
|
|
||||||
R/QaUNbrCjTGYfBsjGbIzmkWPUyTec2ZdRyJ8JiVl386+6CZkxnndQ==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
""",
|
|
||||||
"""
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEpDCCAowCCQC43PUTWSADVjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
|
||||||
b2NhbGhvc3QwHhcNMjIxMDE3MjA0NTM0WhcNMjMxMDE3MjA0NTM0WjAUMRIwEAYD
|
|
||||||
VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDV
|
|
||||||
x1cdEd2ffQTlTXWRiCHGcrlYf4RJnctt9sw/BuHWTLXBu5LhyJSGn5LRszO/NCXK
|
|
||||||
Z/cmGR7pLj366RtiwL+Qo3nhvDCK7T9xZeNIusM6XMcMK9D/DGCYPqtjQz8NXd9V
|
|
||||||
ajBBe6nwTDTa+oqX8Mt89foWNkg5Il/lY62u9Dr18LRZ2W9zzYi3Q9/K0CbIX6pM
|
|
||||||
yVlPIO5rITOR2IsbeyqsO9jufgX5lP4ZKLLBAP1b7usjC4YdvWacjQg/rK5aay1x
|
|
||||||
jC2HCDgo/4N30QVXzSA9nFfSe6AE/xkStK4819JqOkY5JsJCbef1P3hOOdSLEjbp
|
|
||||||
xq3MjOs6G6dOgteaAGs10vx7dHxDWETTIiD7BIZ9zRYgOF5bkCaIUO+JfySE1MHD
|
|
||||||
KBAFLoRuvmRev5Ln5R0MCHpUMSmMNgJqz+RWZV3g/gpYbuWiHgJOwL1393eK50Bg
|
|
||||||
W7SXQ8EjJj2yXZSH+1gPzN0DRoJZiaBoTPnCL2qUgvwFpW1PJsM5FDyUJFUoK5kK
|
|
||||||
HLBBSKAPt6ZlSrUe2nBgJv7EF1GK+fTU08LXgW33OpLceGPa0zTShkukQUMtUtZ8
|
|
||||||
GqhO12ohMzEupIu5Xurthq4VVUrzHUdj1ZZRMhAbfLU36sd03MMyL/xBqTN6dzCa
|
|
||||||
GDGIPGpYjAllZ5xMRt2kZdv+Kr6oo3u2nLUIsqI7KQIDAQABMA0GCSqGSIb3DQEB
|
|
||||||
CwUAA4ICAQCB5s43YF35ssf5YONW5iAaifGpi1o0866xfeOybtohFGvQ7V2W34i9
|
|
||||||
TYBCt8+0hgatMcvZ08f0vqig1i7nrvYcE1hnhL7JNkU8qm0s9ytHZt6j62nB0kd/
|
|
||||||
uqE2hOEQalTf/2TGPV0CCgiqLyd8lEUQvQeA38wktwUeZpVnErlzHeMR2CvV3K8R
|
|
||||||
u4vV6SnBcf+TAt56RKYZkPyvZj5llQPo14Glyoo8qZES7Ky1SHmM0GL+baPRBjRW
|
|
||||||
3KgSt98Wyu4yr9qu21JpnbAnLhBfzfSKjSeCRgFElUE1GIaFGRZ7ypA74dUKeLnb
|
|
||||||
/VUWrszmUhGaEjV9dpI6x6B/kSpQMtIQqBaKRY2ALUeEujS/rURi4iMDwSU+GkSH
|
|
||||||
cyEvZKS97OA/dWeXfLXdo4beDBRG93bI4rQnDg5+VdlBOkQSLueb8x6/VThMoC5d
|
|
||||||
vZiotFQHseljQAdTkNa6tBu6c4XDYPCKB3CfkMYOlCfTS7Acn5G6dxTPKBtLGBnL
|
|
||||||
nQfYyzuwYkN09+2PVzt6auBHr3To7uoclkxX+hxyvPIwIZ0N6b4tQR1FCAkvg29Q
|
|
||||||
WIOjZOKGW690ESKCKOnFjUHVO0HpuWnT81URTuY62FXsYdVc2wE4v0E04mEbqQ0P
|
|
||||||
lY6ZKNA81Lm3YADYtObmK1IUrOPo9BeIaPy0UM08SmN880Vunqa91Q==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
"""));
|
|
||||||
|
|
||||||
secureStorageClient = new SecureStorageClient(credentialGenerator, httpExecutor, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -115,7 +114,7 @@ class SecureStorageClientTest {
|
||||||
final String username = RandomStringUtils.randomAlphabetic(16);
|
final String username = RandomStringUtils.randomAlphabetic(16);
|
||||||
final String password = RandomStringUtils.randomAlphanumeric(32);
|
final String password = RandomStringUtils.randomAlphanumeric(32);
|
||||||
|
|
||||||
when(credentialGenerator.generateFor(accountUuid.toString())).thenReturn(new ExternalServiceCredentials(username, password));
|
when(credentialsGenerator.generateForUuid(accountUuid)).thenReturn(new ExternalServiceCredentials(username, password));
|
||||||
|
|
||||||
wireMock.stubFor(delete(urlEqualTo(SecureStorageClient.DELETE_PATH))
|
wireMock.stubFor(delete(urlEqualTo(SecureStorageClient.DELETE_PATH))
|
||||||
.withBasicAuth(username, password)
|
.withBasicAuth(username, password)
|
||||||
|
@ -130,7 +129,7 @@ class SecureStorageClientTest {
|
||||||
final String username = RandomStringUtils.randomAlphabetic(16);
|
final String username = RandomStringUtils.randomAlphabetic(16);
|
||||||
final String password = RandomStringUtils.randomAlphanumeric(32);
|
final String password = RandomStringUtils.randomAlphanumeric(32);
|
||||||
|
|
||||||
when(credentialGenerator.generateFor(accountUuid.toString())).thenReturn(new ExternalServiceCredentials(username, password));
|
when(credentialsGenerator.generateForUuid(accountUuid)).thenReturn(new ExternalServiceCredentials(username, password));
|
||||||
|
|
||||||
wireMock.stubFor(delete(urlEqualTo(SecureStorageClient.DELETE_PATH))
|
wireMock.stubFor(delete(urlEqualTo(SecureStorageClient.DELETE_PATH))
|
||||||
.withBasicAuth(username, password)
|
.withBasicAuth(username, password)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 Signal Messenger, LLC
|
* Copyright 2013 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -8,15 +8,18 @@ package org.whispersystems.textsecuregcm.tests.auth;
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
|
||||||
class ExternalServiceCredentialsGeneratorTest {
|
class ExternalServiceCredentialsGeneratorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGenerateDerivedUsername() {
|
void testGenerateDerivedUsername() {
|
||||||
ExternalServiceCredentialGenerator generator = new ExternalServiceCredentialGenerator(new byte[32], new byte[32]);
|
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator
|
||||||
ExternalServiceCredentials credentials = generator.generateFor("+14152222222");
|
.builder(new byte[32])
|
||||||
|
.withUserDerivationKey(new byte[32])
|
||||||
|
.build();
|
||||||
|
final ExternalServiceCredentials credentials = generator.generateFor("+14152222222");
|
||||||
|
|
||||||
assertThat(credentials.username()).isNotEqualTo("+14152222222");
|
assertThat(credentials.username()).isNotEqualTo("+14152222222");
|
||||||
assertThat(credentials.password().startsWith("+14152222222")).isFalse();
|
assertThat(credentials.password().startsWith("+14152222222")).isFalse();
|
||||||
|
@ -24,8 +27,10 @@ class ExternalServiceCredentialsGeneratorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGenerateNoDerivedUsername() {
|
void testGenerateNoDerivedUsername() {
|
||||||
ExternalServiceCredentialGenerator generator = new ExternalServiceCredentialGenerator(new byte[32], new byte[32], false);
|
final ExternalServiceCredentialsGenerator generator = ExternalServiceCredentialsGenerator
|
||||||
ExternalServiceCredentials credentials = generator.generateFor("+14152222222");
|
.builder(new byte[32])
|
||||||
|
.build();
|
||||||
|
final ExternalServiceCredentials credentials = generator.generateFor("+14152222222");
|
||||||
|
|
||||||
assertThat(credentials.username()).isEqualTo("+14152222222");
|
assertThat(credentials.username()).isEqualTo("+14152222222");
|
||||||
assertThat(credentials.password().startsWith("+14152222222")).isTrue();
|
assertThat(credentials.password().startsWith("+14152222222")).isTrue();
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -16,21 +16,29 @@ import io.dropwizard.testing.junit5.ResourceExtension;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.ArtServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.controllers.ArtController;
|
import org.whispersystems.textsecuregcm.controllers.ArtController;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.MockHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class ArtControllerTest {
|
class ArtControllerTest {
|
||||||
|
|
||||||
private static final ExternalServiceCredentialGenerator artCredentialGenerator = new ExternalServiceCredentialGenerator(
|
private static final ArtServiceConfiguration ART_SERVICE_CONFIGURATION = MockHelper.buildMock(
|
||||||
new byte[32], new byte[32], true, false, false);
|
ArtServiceConfiguration.class,
|
||||||
|
cfg -> {
|
||||||
|
Mockito.when(cfg.getUserAuthenticationTokenSharedSecret()).thenReturn(new byte[32]);
|
||||||
|
Mockito.when(cfg.getUserAuthenticationTokenUserIdSecret()).thenReturn(new byte[32]);
|
||||||
|
});
|
||||||
|
private static final ExternalServiceCredentialsGenerator artCredentialsGenerator = ArtController.credentialsGenerator(ART_SERVICE_CONFIGURATION);
|
||||||
private static final RateLimiter rateLimiter = mock(RateLimiter.class);
|
private static final RateLimiter rateLimiter = mock(RateLimiter.class);
|
||||||
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||||
|
|
||||||
|
@ -40,7 +48,7 @@ class ArtControllerTest {
|
||||||
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new ArtController(rateLimiters, artCredentialGenerator))
|
.addResource(new ArtController(rateLimiters, artCredentialsGenerator))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@Test
|
@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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -26,15 +26,15 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.controllers.DirectoryController;
|
import org.whispersystems.textsecuregcm.controllers.DirectoryController;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class DirectoryControllerTest {
|
class DirectoryControllerTest {
|
||||||
|
|
||||||
private static final ExternalServiceCredentialGenerator directoryCredentialsGenerator = mock(ExternalServiceCredentialGenerator.class);
|
private static final ExternalServiceCredentialsGenerator directoryCredentialsGenerator = mock(ExternalServiceCredentialsGenerator.class);
|
||||||
private static final ExternalServiceCredentials validCredentials = new ExternalServiceCredentials("username", "password");
|
private static final ExternalServiceCredentials validCredentials = new ExternalServiceCredentials("username", "password");
|
||||||
|
|
||||||
private static final ResourceExtension resources = ResourceExtension.builder()
|
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2021 Signal Messenger, LLC
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -15,8 +15,9 @@ import java.time.ZoneId;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.DirectoryV2ClientConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.controllers.DirectoryV2Controller;
|
import org.whispersystems.textsecuregcm.controllers.DirectoryV2Controller;
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
@ -26,11 +27,12 @@ class DirectoryControllerV2Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAuthToken() {
|
void testAuthToken() {
|
||||||
final ExternalServiceCredentialGenerator credentialGenerator = new ExternalServiceCredentialGenerator(
|
final ExternalServiceCredentialsGenerator credentialsGenerator = DirectoryV2Controller.credentialsGenerator(
|
||||||
new byte[]{0x1}, new byte[]{0x2}, true, false,
|
new DirectoryV2ClientConfiguration(new byte[]{0x1}, new byte[]{0x2}),
|
||||||
Clock.fixed(Instant.ofEpochSecond(1633738643L), ZoneId.of("Etc/UTC")));
|
Clock.fixed(Instant.ofEpochSecond(1633738643L), ZoneId.of("Etc/UTC"))
|
||||||
|
);
|
||||||
|
|
||||||
final DirectoryV2Controller controller = new DirectoryV2Controller(credentialGenerator);
|
final DirectoryV2Controller controller = new DirectoryV2Controller(credentialsGenerator);
|
||||||
|
|
||||||
final Account account = mock(Account.class);
|
final Account account = mock(Account.class);
|
||||||
final UUID uuid = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
final UUID uuid = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
import org.whispersystems.textsecuregcm.controllers.PaymentsController;
|
import org.whispersystems.textsecuregcm.controllers.PaymentsController;
|
||||||
import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager;
|
import org.whispersystems.textsecuregcm.currency.CurrencyConversionManager;
|
||||||
import org.whispersystems.textsecuregcm.entities.CurrencyConversionEntity;
|
import org.whispersystems.textsecuregcm.entities.CurrencyConversionEntity;
|
||||||
|
@ -36,7 +36,7 @@ import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class PaymentsControllerTest {
|
class PaymentsControllerTest {
|
||||||
|
|
||||||
private static final ExternalServiceCredentialGenerator paymentsCredentialGenerator = mock(ExternalServiceCredentialGenerator.class);
|
private static final ExternalServiceCredentialsGenerator paymentsCredentialsGenerator = mock(ExternalServiceCredentialsGenerator.class);
|
||||||
private static final CurrencyConversionManager currencyManager = mock(CurrencyConversionManager.class);
|
private static final CurrencyConversionManager currencyManager = mock(CurrencyConversionManager.class);
|
||||||
|
|
||||||
private final ExternalServiceCredentials validCredentials = new ExternalServiceCredentials("username", "password");
|
private final ExternalServiceCredentials validCredentials = new ExternalServiceCredentials("username", "password");
|
||||||
|
@ -46,13 +46,13 @@ class PaymentsControllerTest {
|
||||||
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
|
||||||
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new PaymentsController(currencyManager, paymentsCredentialGenerator))
|
.addResource(new PaymentsController(currencyManager, paymentsCredentialsGenerator))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() {
|
void setup() {
|
||||||
when(paymentsCredentialGenerator.generateFor(eq(AuthHelper.VALID_UUID.toString()))).thenReturn(validCredentials);
|
when(paymentsCredentialsGenerator.generateForUuid(eq(AuthHelper.VALID_UUID))).thenReturn(validCredentials);
|
||||||
when(currencyManager.getCurrencyConversions()).thenReturn(Optional.of(
|
when(currencyManager.getCurrencyConversions()).thenReturn(Optional.of(
|
||||||
new CurrencyConversionEntityList(List.of(
|
new CurrencyConversionEntityList(List.of(
|
||||||
new CurrencyConversionEntity("FOO", Map.of(
|
new CurrencyConversionEntity("FOO", Map.of(
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* 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.tests.controllers;
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
|
@ -17,16 +18,23 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator;
|
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.SecureStorageServiceConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
import org.whispersystems.textsecuregcm.controllers.SecureStorageController;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.MockHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class SecureStorageControllerTest {
|
class SecureStorageControllerTest {
|
||||||
|
|
||||||
private static final ExternalServiceCredentialGenerator storageCredentialGenerator = new ExternalServiceCredentialGenerator(new byte[32], new byte[32], false);
|
private static final SecureStorageServiceConfiguration STORAGE_CFG = MockHelper.buildMock(
|
||||||
|
SecureStorageServiceConfiguration.class,
|
||||||
|
cfg -> when(cfg.decodeUserAuthenticationTokenSharedSecret()).thenReturn(new byte[32]));
|
||||||
|
|
||||||
|
private static final ExternalServiceCredentialsGenerator STORAGE_CREDENTIAL_GENERATOR = SecureStorageController
|
||||||
|
.credentialsGenerator(STORAGE_CFG);
|
||||||
|
|
||||||
private static final ResourceExtension resources = ResourceExtension.builder()
|
private static final ResourceExtension resources = ResourceExtension.builder()
|
||||||
.addProvider(AuthHelper.getAuthFilter())
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
|
@ -34,7 +42,7 @@ class SecureStorageControllerTest {
|
||||||
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
||||||
.setMapper(SystemMapper.getMapper())
|
.setMapper(SystemMapper.getMapper())
|
||||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
.addResource(new SecureStorageController(storageCredentialGenerator))
|
.addResource(new SecureStorageController(STORAGE_CREDENTIAL_GENERATOR))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +68,4 @@ class SecureStorageControllerTest {
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(401);
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2013-2021 Signal Messenger, LLC
|
* Copyright 2013-2023 Signal Messenger, LLC
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ package org.whispersystems.textsecuregcm.tests.util;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.any;
|
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ -26,10 +25,10 @@ import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticator;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
|
||||||
import org.whispersystems.textsecuregcm.storage.Account;
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
|
import org.whispersystems.textsecuregcm.util.HeaderUtils;
|
||||||
|
|
||||||
public class AuthHelper {
|
public class AuthHelper {
|
||||||
// Static seed to ensure reproducible tests.
|
// Static seed to ensure reproducible tests.
|
||||||
|
@ -201,19 +200,15 @@ public class AuthHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAuthHeader(UUID uuid, long deviceId, String password) {
|
public static String getAuthHeader(UUID uuid, long deviceId, String password) {
|
||||||
return getAuthHeader(uuid.toString() + "." + deviceId, password);
|
return HeaderUtils.basicAuthHeader(uuid.toString() + "." + deviceId, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAuthHeader(UUID uuid, String password) {
|
public static String getAuthHeader(UUID uuid, String password) {
|
||||||
return getAuthHeader(uuid.toString(), password);
|
return HeaderUtils.basicAuthHeader(uuid.toString(), password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getProvisioningAuthHeader(String number, String password) {
|
public static String getProvisioningAuthHeader(String number, String password) {
|
||||||
return getAuthHeader(number, password);
|
return HeaderUtils.basicAuthHeader(number, password);
|
||||||
}
|
|
||||||
|
|
||||||
private static String getAuthHeader(String identifier, String password) {
|
|
||||||
return "Basic " + Base64.getEncoder().encodeToString((identifier + ":" + password).getBytes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getUnidentifiedAccessHeader(byte[] key) {
|
public static String getUnidentifiedAccessHeader(byte[] key) {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
public final class MockHelper {
|
||||||
|
|
||||||
|
private MockHelper() {
|
||||||
|
// utility class
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface MockInitializer<T> {
|
||||||
|
|
||||||
|
void init(T mock) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T buildMock(final Class<T> clazz, final MockInitializer<T> initializer) throws RuntimeException {
|
||||||
|
final T mock = Mockito.mock(clazz);
|
||||||
|
try {
|
||||||
|
initializer.init(mock);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue