Use `java.util` Hex and Base64 codecs

This commit is contained in:
Chris Eager 2023-02-06 12:16:59 -06:00 committed by GitHub
parent 3bbab0027b
commit 358a286523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 118 additions and 250 deletions

View File

@ -48,7 +48,6 @@
<aws.sdk.version>1.12.376</aws.sdk.version>
<aws.sdk2.version>2.19.8</aws.sdk2.version>
<braintree.version>3.19.0</braintree.version>
<commons-codec.version>1.15</commons-codec.version>
<commons-csv.version>1.9.0</commons-csv.version>
<commons-io.version>2.9.0</commons-io.version>
<dropwizard.version>2.0.34</dropwizard.version>
@ -187,11 +186,6 @@
<artifactId>semver4j</artifactId>
<version>${semver4j.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>

View File

@ -173,10 +173,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>

View File

@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Hex;
import java.util.HexFormat;
import org.signal.libsignal.protocol.kdf.HKDF;
public record SaltedTokenHash(String hash, String salt) {
@ -52,13 +52,13 @@ public record SaltedTokenHash(String hash, String salt) {
private static String generateSalt() {
final byte[] salt = new byte[SALT_SIZE];
SECURE_RANDOM.nextBytes(salt);
return Hex.encodeHexString(salt);
return HexFormat.of().formatHex(salt);
}
private static String calculateV1Hash(final String salt, final String token) {
try {
return new String(
Hex.encodeHex(MessageDigest.getInstance("SHA1").digest((salt + token).getBytes(StandardCharsets.UTF_8))));
return HexFormat.of()
.formatHex(MessageDigest.getInstance("SHA1").digest((salt + token).getBytes(StandardCharsets.UTF_8)));
} catch (final NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
@ -70,6 +70,6 @@ public record SaltedTokenHash(String hash, String salt) {
salt.getBytes(StandardCharsets.UTF_8), // salt
AUTH_TOKEN_HKDF_INFO,
32);
return V2_PREFIX + Hex.encodeHexString(secret);
return V2_PREFIX + HexFormat.of().formatHex(secret);
}
}

View File

@ -6,10 +6,8 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.time.Duration;
import java.util.HexFormat;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ -27,12 +25,12 @@ public class ArtServiceConfiguration {
@NotNull
private Duration tokenExpiration = Duration.ofDays(1);
public byte[] getUserAuthenticationTokenSharedSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
public byte[] getUserAuthenticationTokenSharedSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenSharedSecret);
}
public byte[] getUserAuthenticationTokenUserIdSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenUserIdSecret.toCharArray());
public byte[] getUserAuthenticationTokenUserIdSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenUserIdSecret);
}
public Duration getTokenExpiration() {

View File

@ -5,9 +5,8 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HexFormat;
import javax.validation.constraints.NotEmpty;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
public class DirectoryClientConfiguration {
@ -19,12 +18,12 @@ public class DirectoryClientConfiguration {
@JsonProperty
private String userAuthenticationTokenUserIdSecret;
public byte[] getUserAuthenticationTokenSharedSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
public byte[] getUserAuthenticationTokenSharedSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenSharedSecret);
}
public byte[] getUserAuthenticationTokenUserIdSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenUserIdSecret.toCharArray());
public byte[] getUserAuthenticationTokenUserIdSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenUserIdSecret);
}
}

View File

@ -6,13 +6,11 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
public class PaymentsServiceConfiguration {
@ -36,8 +34,8 @@ public class PaymentsServiceConfiguration {
@JsonProperty
private List<String> paymentCurrencies;
public byte[] getUserAuthenticationTokenSharedSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
public byte[] getUserAuthenticationTokenSharedSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenSharedSecret);
}
public String getCoinMarketCapApiKey() {

View File

@ -6,14 +6,13 @@
package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
import java.util.HexFormat;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.util.List;
public class SecureBackupServiceConfiguration {
@ -39,8 +38,8 @@ public class SecureBackupServiceConfiguration {
@JsonProperty
private RetryConfiguration retry = new RetryConfiguration();
public byte[] getUserAuthenticationTokenSharedSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
public byte[] getUserAuthenticationTokenSharedSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenSharedSecret);
}
@VisibleForTesting

View File

@ -5,12 +5,11 @@
package org.whispersystems.textsecuregcm.configuration;
import java.util.HexFormat;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
public record SecureStorageServiceConfiguration(@NotEmpty String userAuthenticationTokenSharedSecret,
@NotBlank String uri,
@ -27,7 +26,7 @@ public record SecureStorageServiceConfiguration(@NotEmpty String userAuthenticat
}
}
public byte[] decodeUserAuthenticationTokenSharedSecret() throws DecoderException {
return Hex.decodeHex(userAuthenticationTokenSharedSecret.toCharArray());
public byte[] decodeUserAuthenticationTokenSharedSecret() {
return HexFormat.of().parseHex(userAuthenticationTokenSharedSecret);
}
}

View File

@ -27,6 +27,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HexFormat;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
@ -108,7 +109,6 @@ import org.whispersystems.textsecuregcm.storage.UsernameHashNotAvailableExceptio
import org.whispersystems.textsecuregcm.storage.UsernameReservationNotFoundException;
import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.HeaderUtils;
import org.whispersystems.textsecuregcm.util.Hex;
import org.whispersystems.textsecuregcm.util.ImpossiblePhoneNumberException;
import org.whispersystems.textsecuregcm.util.NonNormalizedPhoneNumberException;
import org.whispersystems.textsecuregcm.util.Optionals;
@ -947,7 +947,7 @@ public class AccountController {
byte[] challenge = new byte[16];
random.nextBytes(challenge);
return Hex.toStringCondensed(challenge);
return HexFormat.of().formatHex(challenge);
}
private byte[] createRegistrationSession(final Phonenumber.PhoneNumber phoneNumber) throws RateLimitExceededException {

View File

@ -12,7 +12,6 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.DecoderException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
@ -25,16 +24,12 @@ public class ArtController {
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);
}
return ExternalServiceCredentialsGenerator
.builder(cfg.getUserAuthenticationTokenSharedSecret())
.withUserDerivationKey(cfg.getUserAuthenticationTokenUserIdSecret())
.prependUsername(false)
.truncateSignature(false)
.build();
}
public ArtController(RateLimiters rateLimiters,

View File

@ -13,7 +13,6 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.codec.DecoderException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
import org.whispersystems.textsecuregcm.configuration.DirectoryClientConfiguration;
@ -23,8 +22,7 @@ public class DirectoryController {
private final ExternalServiceCredentialsGenerator directoryServiceTokenGenerator;
public static ExternalServiceCredentialsGenerator credentialsGenerator(final DirectoryClientConfiguration cfg)
throws DecoderException {
public static ExternalServiceCredentialsGenerator credentialsGenerator(final DirectoryClientConfiguration cfg) {
return ExternalServiceCredentialsGenerator
.builder(cfg.getUserAuthenticationTokenSharedSecret())
.withUserDerivationKey(cfg.getUserAuthenticationTokenUserIdSecret())

View File

@ -11,7 +11,6 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.DecoderException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
@ -25,17 +24,17 @@ public class PaymentsController {
private final ExternalServiceCredentialsGenerator paymentsServiceCredentialsGenerator;
private final CurrencyConversionManager currencyManager;
public static ExternalServiceCredentialsGenerator credentialsGenerator(final PaymentsServiceConfiguration cfg)
throws DecoderException {
public static ExternalServiceCredentialsGenerator credentialsGenerator(final PaymentsServiceConfiguration cfg) {
return ExternalServiceCredentialsGenerator
.builder(cfg.getUserAuthenticationTokenSharedSecret())
.prependUsername(true)
.build();
}
public PaymentsController(final CurrencyConversionManager currencyManager, final ExternalServiceCredentialsGenerator paymentsServiceCredentialsGenerator) {
this.currencyManager = currencyManager;
public PaymentsController(final CurrencyConversionManager currencyManager,
final ExternalServiceCredentialsGenerator paymentsServiceCredentialsGenerator) {
this.currencyManager = currencyManager;
this.paymentsServiceCredentialsGenerator = paymentsServiceCredentialsGenerator;
}

View File

@ -29,6 +29,7 @@ import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.HexFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@ -64,8 +65,6 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.VerificationFailedException;
@ -530,10 +529,11 @@ public class ProfileController {
final UUID uuid) {
try {
final ProfileKeyCommitment commitment = new ProfileKeyCommitment(profile.getCommitment());
final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(Hex.decodeHex(encodedProfileCredentialRequest));
final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(
HexFormat.of().parseHex(encodedProfileCredentialRequest));
return zkProfileOperations.issueProfileKeyCredential(request, uuid, commitment);
} catch (DecoderException | VerificationFailedException | InvalidInputException e) {
} catch (IllegalArgumentException | VerificationFailedException | InvalidInputException e) {
throw new WebApplicationException(e, Response.status(Response.Status.BAD_REQUEST).build());
}
}
@ -545,10 +545,11 @@ public class ProfileController {
try {
final ProfileKeyCommitment commitment = new ProfileKeyCommitment(profile.getCommitment());
final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(Hex.decodeHex(encodedCredentialRequest));
final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(
HexFormat.of().parseHex(encodedCredentialRequest));
return zkProfileOperations.issuePniCredential(request, accountIdentifier, phoneNumberIdentifier, commitment);
} catch (DecoderException | VerificationFailedException | InvalidInputException e) {
} catch (IllegalArgumentException | VerificationFailedException | InvalidInputException e) {
throw new WebApplicationException(e, Response.status(Response.Status.BAD_REQUEST).build());
}
}
@ -561,10 +562,11 @@ public class ProfileController {
try {
final ProfileKeyCommitment commitment = new ProfileKeyCommitment(profile.getCommitment());
final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(Hex.decodeHex(encodedCredentialRequest));
final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(
HexFormat.of().parseHex(encodedCredentialRequest));
return zkProfileOperations.issueExpiringProfileKeyCredential(request, accountIdentifier, commitment, expiration);
} catch (DecoderException | VerificationFailedException | InvalidInputException e) {
} catch (IllegalArgumentException | VerificationFailedException | InvalidInputException e) {
throw new WebApplicationException(e, Response.status(Response.Status.BAD_REQUEST).build());
}
}

View File

@ -24,7 +24,6 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.lang3.tuple.Pair;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
@ -53,15 +52,11 @@ public class SecureBackupController {
public static ExternalServiceCredentialsGenerator credentialsGenerator(
final SecureBackupServiceConfiguration cfg,
final Clock clock) {
try {
return ExternalServiceCredentialsGenerator
.builder(cfg.getUserAuthenticationTokenSharedSecret())
.prependUsername(true)
.withClock(clock)
.build();
} catch (final DecoderException e) {
throw new IllegalStateException(e);
}
return ExternalServiceCredentialsGenerator
.builder(cfg.getUserAuthenticationTokenSharedSecret())
.prependUsername(true)
.withClock(clock)
.build();
}
public SecureBackupController(

View File

@ -11,7 +11,6 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.DecoderException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
@ -23,14 +22,10 @@ public class SecureStorageController {
private final ExternalServiceCredentialsGenerator storageServiceCredentialsGenerator;
public static ExternalServiceCredentialsGenerator credentialsGenerator(final SecureStorageServiceConfiguration cfg) {
try {
return ExternalServiceCredentialsGenerator
.builder(cfg.decodeUserAuthenticationTokenSharedSecret())
.prependUsername(true)
.build();
} catch (DecoderException e) {
throw new IllegalArgumentException(e);
}
return ExternalServiceCredentialsGenerator
.builder(cfg.decodeUserAuthenticationTokenSharedSecret())
.prependUsername(true)
.build();
}
public SecureStorageController(ExternalServiceCredentialsGenerator storageServiceCredentialsGenerator) {

View File

@ -11,7 +11,6 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.codec.DecoderException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentials;
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
@ -20,8 +19,7 @@ import org.whispersystems.textsecuregcm.configuration.SecureValueRecovery2Config
@Path("/v2/backup")
public class SecureValueRecovery2Controller {
public static ExternalServiceCredentialsGenerator credentialsGenerator(final SecureValueRecovery2Configuration cfg)
throws DecoderException {
public static ExternalServiceCredentialsGenerator credentialsGenerator(final SecureValueRecovery2Configuration cfg) {
return ExternalServiceCredentialsGenerator
.builder(cfg.userAuthenticationTokenSharedSecret())
.withUserDerivationKey(cfg.userIdTokenSharedSecret())

View File

@ -9,6 +9,7 @@ import io.dropwizard.auth.Auth;
import java.security.SecureRandom;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.HexFormat;
import java.util.LinkedList;
import java.util.List;
import javax.validation.constraints.Max;
@ -25,7 +26,6 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.s3.PolicySigner;
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
import org.whispersystems.textsecuregcm.util.Constants;
import org.whispersystems.textsecuregcm.util.Hex;
import org.whispersystems.textsecuregcm.util.Pair;
@Path("/v1/sticker")
@ -78,7 +78,7 @@ public class StickerController {
byte[] object = new byte[16];
new SecureRandom().nextBytes(object);
return Hex.toStringCondensed(object);
return HexFormat.of().formatHex(object);
}
}

View File

@ -17,10 +17,10 @@ import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HexFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import org.apache.commons.codec.binary.Hex;
public class CanonicalRequestSigner {
@ -52,7 +52,7 @@ public class CanonicalRequestSigner {
throw new AssertionError(e);
}
sha256.update(canonicalRequest.getCanonicalRequest().getBytes(StandardCharsets.UTF_8));
result.append(Hex.encodeHex(sha256.digest()));
result.append(HexFormat.of().formatHex(sha256.digest()));
return result.toString();
}
@ -67,7 +67,7 @@ public class CanonicalRequestSigner {
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
throw new AssertionError(e);
}
return Hex.encodeHexString(signature);
return HexFormat.of().formatHex(signature);
}
private static PrivateKey initializeRsaSigningKey(String rsaSigningKey) throws IOException, InvalidKeyException, InvalidKeySpecException {

View File

@ -10,8 +10,7 @@ import static com.codahale.metrics.MetricRegistry.name;
import io.micrometer.core.instrument.Metrics;
import java.security.SecureRandom;
import java.time.Duration;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import java.util.HexFormat;
import org.apache.commons.lang3.StringUtils;
import org.whispersystems.textsecuregcm.push.NotPushRegisteredException;
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
@ -55,7 +54,7 @@ public class PushChallengeManager {
final String platform;
if (pushChallengeDynamoDb.add(account.getUuid(), token, CHALLENGE_TTL)) {
pushNotificationManager.sendRateLimitChallengeNotification(account, Hex.encodeHexString(token));
pushNotificationManager.sendRateLimitChallengeNotification(account, HexFormat.of().formatHex(token));
sent = true;
@ -83,8 +82,8 @@ public class PushChallengeManager {
boolean success = false;
try {
success = pushChallengeDynamoDb.remove(account.getUuid(), Hex.decodeHex(challengeTokenHex));
} catch (final DecoderException ignored) {
success = pushChallengeDynamoDb.remove(account.getUuid(), HexFormat.of().parseHex(challengeTokenHex));
} catch (final IllegalArgumentException ignored) {
}
final String platform = account.getMasterDevice().map(masterDevice -> {

View File

@ -15,9 +15,9 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
@ -60,7 +60,7 @@ public class ClusterLuaScript {
this.script = script;
try {
this.sha = Hex.encodeHexString(MessageDigest.getInstance("SHA-1").digest(script.getBytes(StandardCharsets.UTF_8)));
this.sha = HexFormat.of().formatHex(MessageDigest.getInstance("SHA-1").digest(script.getBytes(StandardCharsets.UTF_8)));
} catch (final NoSuchAlgorithmException e) {
// All Java implementations are required to support SHA-1, so this should never happen
throw new AssertionError(e);

View File

@ -5,12 +5,11 @@
package org.whispersystems.textsecuregcm.s3;
import org.apache.commons.codec.binary.Base64;
import org.whispersystems.textsecuregcm.util.Pair;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import org.whispersystems.textsecuregcm.util.Pair;
public class PostPolicyGenerator {
@ -28,30 +27,26 @@ public class PostPolicyGenerator {
}
public Pair<String, String> createFor(ZonedDateTime now, String object, int maxSizeInBytes) {
try {
String expiration = now.plusMinutes(30).format(DateTimeFormatter.ISO_INSTANT);
String credentialDate = now.format(CREDENTIAL_DATE);
String requestDate = now.format(AWS_DATE_TIME );
String credential = String.format("%s/%s/%s/s3/aws4_request", awsAccessId, credentialDate, region);
String expiration = now.plusMinutes(30).format(DateTimeFormatter.ISO_INSTANT);
String credentialDate = now.format(CREDENTIAL_DATE);
String requestDate = now.format(AWS_DATE_TIME);
String credential = String.format("%s/%s/%s/s3/aws4_request", awsAccessId, credentialDate, region);
String policy = String.format("{ \"expiration\": \"%s\",\n" +
" \"conditions\": [\n" +
" {\"bucket\": \"%s\"},\n" +
" {\"key\": \"%s\"},\n" +
" {\"acl\": \"private\"},\n" +
" [\"starts-with\", \"$Content-Type\", \"\"],\n" +
" [\"content-length-range\", 1, " + maxSizeInBytes + "],\n" +
"\n" +
" {\"x-amz-credential\": \"%s\"},\n" +
" {\"x-amz-algorithm\": \"AWS4-HMAC-SHA256\"},\n" +
" {\"x-amz-date\": \"%s\" }\n" +
" ]\n" +
"}", expiration, bucket, object, credential, requestDate);
String policy = String.format("{ \"expiration\": \"%s\",\n" +
" \"conditions\": [\n" +
" {\"bucket\": \"%s\"},\n" +
" {\"key\": \"%s\"},\n" +
" {\"acl\": \"private\"},\n" +
" [\"starts-with\", \"$Content-Type\", \"\"],\n" +
" [\"content-length-range\", 1, " + maxSizeInBytes + "],\n" +
"\n" +
" {\"x-amz-credential\": \"%s\"},\n" +
" {\"x-amz-algorithm\": \"AWS4-HMAC-SHA256\"},\n" +
" {\"x-amz-date\": \"%s\" }\n" +
" ]\n" +
"}", expiration, bucket, object, credential, requestDate);
return new Pair<>(credential, Base64.encodeBase64String(policy.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
return new Pair<>(credential, Base64.getEncoder().encodeToString(policy.getBytes(StandardCharsets.UTF_8)));
}
}

View File

@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Comparator;
import java.util.HexFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -35,7 +36,6 @@ import javax.annotation.Nullable;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
@ -233,7 +233,7 @@ public class BraintreeManager implements SubscriptionProcessorManager {
public CompletableFuture<ProcessorCustomer> createCustomer(final byte[] subscriberUser) {
return CompletableFuture.supplyAsync(() -> {
final CustomerRequest request = new CustomerRequest()
.customField("subscriber_user", Hex.encodeHexString(subscriberUser));
.customField("subscriber_user", HexFormat.of().formatHex(subscriberUser));
try {
return braintreeGateway.customer().create(request);
} catch (BraintreeException e) {

View File

@ -44,6 +44,7 @@ import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HexFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -61,7 +62,6 @@ import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.whispersystems.textsecuregcm.util.Conversions;
@ -124,7 +124,7 @@ public class StripeManager implements SubscriptionProcessorManager {
public CompletableFuture<ProcessorCustomer> createCustomer(byte[] subscriberUser) {
return CompletableFuture.supplyAsync(() -> {
CustomerCreateParams params = CustomerCreateParams.builder()
.putMetadata("subscriberUser", Hex.encodeHexString(subscriberUser))
.putMetadata("subscriberUser", HexFormat.of().formatHex(subscriberUser))
.build();
try {
return Customer.create(params, commonOptions(generateIdempotencyKeyForSubscriberUser(subscriberUser)));

View File

@ -1,98 +0,0 @@
/*
* Copyright 2013-2020 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
/**
* Utility for generating hex dumps a la hexl-mode in emacs.
*/
public class Hex {
final static String EOL = System.getProperty("line.separator");
private final static char[] HEX_DIGITS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
public static String toString(byte[] bytes) {
return toString(bytes, 0, bytes.length, false);
}
public static String toStringCondensed(byte[] bytes) {
return toString(bytes, 0, bytes.length, true);
}
public static String toString(byte[] bytes, int offset, int length, boolean condensed) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < length; i++) {
appendHexChar(buf, bytes[offset + i]);
if (!condensed) buf.append(' ');
}
return buf.toString();
}
public static String dump(byte[] bytes) {
return dump(bytes, 0, bytes.length);
}
public static String dump(byte[] bytes, int offset, int length) {
StringBuffer buf = new StringBuffer();
int lines = ((length - 1) / 16) + 1;
int lineOffset;
int lineLength;
for (int i = 0; i < lines; i++) {
lineOffset = (i * 16) + offset;
lineLength = Math.min(16, (length - (i * 16)));
appendDumpLine(buf, i, bytes, lineOffset, lineLength);
buf.append(EOL);
}
return buf.toString();
}
private static void appendDumpLine(StringBuffer buf, int line,
byte[] bytes, int lineOffset,
int lineLength)
{
buf.append(HEX_DIGITS[(line >> 28) & 0xf]);
buf.append(HEX_DIGITS[(line >> 24) & 0xf]);
buf.append(HEX_DIGITS[(line >> 20) & 0xf]);
buf.append(HEX_DIGITS[(line >> 16) & 0xf]);
buf.append(HEX_DIGITS[(line >> 12) & 0xf]);
buf.append(HEX_DIGITS[(line >> 8) & 0xf]);
buf.append(HEX_DIGITS[(line >> 4) & 0xf]);
buf.append(HEX_DIGITS[(line ) & 0xf]);
buf.append(": ");
for (int i = 0; i < 16; i++) {
int idx = i + lineOffset;
if (i < lineLength) {
int b = bytes[idx];
appendHexChar(buf, b);
} else {
buf.append(" ");
}
if ((i % 2) == 1) {
buf.append(' ');
}
}
for (int i = 0; i < 16 && i < lineLength; i++) {
int idx = i + lineOffset;
int b = bytes[idx];
if (b >= 0x20 && b <= 0x7e) {
buf.append((char)b);
} else {
buf.append('.');
}
}
}
private static void appendHexChar(StringBuffer buf, int b) {
buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
buf.append(HEX_DIGITS[b & 0xf]);
}
}

View File

@ -38,6 +38,7 @@ import java.time.Duration;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -114,7 +115,6 @@ import org.whispersystems.textsecuregcm.storage.UsernameHashNotAvailableExceptio
import org.whispersystems.textsecuregcm.storage.UsernameReservationNotFoundException;
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.Hex;
import org.whispersystems.textsecuregcm.util.MockUtils;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.textsecuregcm.util.TestClock;
@ -226,7 +226,8 @@ class AccountControllerTest {
clearInvocations(AuthHelper.VALID_ACCOUNT, AuthHelper.UNDISCOVERABLE_ACCOUNT);
new SecureRandom().nextBytes(registration_lock_key);
SaltedTokenHash registrationLockCredentials = SaltedTokenHash.generateFor(Hex.toStringCondensed(registration_lock_key));
SaltedTokenHash registrationLockCredentials = SaltedTokenHash.generateFor(
HexFormat.of().formatHex(registration_lock_key));
AccountsHelper.setupMockUpdate(accountsManager);
@ -1019,7 +1020,8 @@ class AccountControllerTest {
.target("/v1/accounts/code/666666")
.request()
.header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar"))
.put(Entity.entity(new AccountAttributes(false, 3333, null, Hex.toStringCondensed(registration_lock_key), true, null),
.put(Entity.entity(
new AccountAttributes(false, 3333, null, HexFormat.of().formatHex(registration_lock_key), true, null),
MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class);
assertThat(result.uuid()).isNotNull();
@ -1043,7 +1045,8 @@ class AccountControllerTest {
.target("/v1/accounts/code/666666")
.request()
.header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar"))
.put(Entity.entity(new AccountAttributes(false, 3333, null, Hex.toStringCondensed(registration_lock_key), true, null),
.put(Entity.entity(
new AccountAttributes(false, 3333, null, HexFormat.of().formatHex(registration_lock_key), true, null),
MediaType.APPLICATION_JSON_TYPE), AccountIdentityResponse.class);
assertThat(result.uuid()).isNotNull();
@ -1051,7 +1054,7 @@ class AccountControllerTest {
verify(pinLimiter).validate(eq(SENDER_REG_LOCK));
verify(accountsManager).create(eq(SENDER_REG_LOCK), eq("bar"), any(), argThat(
attributes -> Hex.toStringCondensed(registration_lock_key).equals(attributes.getRegistrationLock())),
attributes -> HexFormat.of().formatHex(registration_lock_key).equals(attributes.getRegistrationLock())),
argThat(List::isEmpty));
}
@ -1104,7 +1107,7 @@ class AccountControllerTest {
.request()
.header("Authorization", AuthHelper.getProvisioningAuthHeader(SENDER_REG_LOCK, "bar"))
.put(Entity.entity(new AccountAttributes(false, 3333, null,
Hex.toStringCondensed(new byte[32]), true, null),
HexFormat.of().formatHex(new byte[32]), true, null),
MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus()).isEqualTo(423);

View File

@ -36,6 +36,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -47,7 +48,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomStringUtils;
import org.assertj.core.api.Condition;
import org.glassfish.jersey.server.ServerProperties;
@ -945,7 +945,8 @@ class ProfileControllerTest {
.thenReturn(credentialResponse);
final ProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version, Hex.encodeHexString(credentialRequest.serialize())))
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
HexFormat.of().formatHex(credentialRequest.serialize())))
.request()
.headers(authHeaders)
.get(ProfileKeyCredentialProfileResponse.class);
@ -1029,7 +1030,8 @@ class ProfileControllerTest {
.thenReturn(credentialResponse);
final PniCredentialProfileResponse profile = resources.getJerseyTest()
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version, Hex.encodeHexString(credentialRequest.serialize())))
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
HexFormat.of().formatHex(credentialRequest.serialize())))
.queryParam("credentialType", "pni")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
@ -1078,7 +1080,8 @@ class ProfileControllerTest {
.thenReturn(credentialResponse);
final Response response = resources.getJerseyTest()
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version, Hex.encodeHexString(credentialRequest.serialize())))
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
HexFormat.of().formatHex(credentialRequest.serialize())))
.queryParam("credentialType", "pni")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
@ -1135,7 +1138,8 @@ class ProfileControllerTest {
.thenReturn(credentialResponse);
final ExpiringProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version, Hex.encodeHexString(credentialRequest.serialize())))
.target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
HexFormat.of().formatHex(credentialRequest.serialize())))
.queryParam("credentialType", "expiringProfileKey")
.request()
.headers(authHeaders)

View File

@ -14,13 +14,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@ -117,7 +117,7 @@ public class ChangeNumberManagerTest {
final IncomingMessage msg = mock(IncomingMessage.class);
when(msg.destinationDeviceId()).thenReturn(2L);
when(msg.content()).thenReturn(Base64.encodeBase64String(new byte[]{1}));
when(msg.content()).thenReturn(Base64.getEncoder().encodeToString(new byte[]{1}));
changeNumberManager.changeNumber(account, changedE164, pniIdentityKey, prekeys, List.of(msg), registrationIds);