/v1/backup/auth/check endpoint added

This commit is contained in:
Sergey Skrobotov
2023-01-30 15:34:28 -08:00
parent 896e65545e
commit dc8f62a4ad
24 changed files with 1334 additions and 197 deletions

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Objects;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
/**
* Constraint annotation that requires annotated entity
* to hold (or return) a string value that is a valid E164-normalized phone number.
*/
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
@Constraint(validatedBy = E164.Validator.class)
@Documented
public @interface E164 {
String message() default "{org.whispersystems.textsecuregcm.util.E164.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
class Validator implements ConstraintValidator<E164, String> {
@Override
public boolean isValid(final String value, final ConstraintValidatorContext context) {
if (Objects.isNull(value)) {
return true;
}
if (!value.startsWith("+")) {
return false;
}
try {
Util.requireNormalizedNumber(value);
} catch (final ImpossiblePhoneNumberException | NonNormalizedPhoneNumberException e) {
return false;
}
return true;
}
}
}

View File

@@ -6,11 +6,12 @@
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.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public final class HmacUtils {
@@ -63,4 +64,14 @@ public final class HmacUtils {
public static String hmac256TruncatedToHexString(final byte[] key, final String input, final int length) {
return hmac256TruncatedToHexString(key, input.getBytes(StandardCharsets.UTF_8), length);
}
public static boolean hmacHexStringsEqual(final String expectedAsHexString, final String actualAsHexString) {
try {
final byte[] aBytes = HEX.parseHex(expectedAsHexString);
final byte[] bBytes = HEX.parseHex(actualAsHexString);
return MessageDigest.isEqual(aBytes, bBytes);
} catch (final IllegalArgumentException e) {
return false;
}
}
}

View File

@@ -7,35 +7,48 @@ package org.whispersystems.textsecuregcm.util;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.UUID;
public class UUIDUtil {
public final class UUIDUtil {
public static byte[] toBytes(final UUID uuid) {
return toByteBuffer(uuid).array();
}
private UUIDUtil() {
// utility class
}
public static ByteBuffer toByteBuffer(final UUID uuid) {
final ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
return byteBuffer.flip();
}
public static byte[] toBytes(final UUID uuid) {
return toByteBuffer(uuid).array();
}
public static UUID fromBytes(final byte[] bytes) {
return fromByteBuffer(ByteBuffer.wrap(bytes));
}
public static ByteBuffer toByteBuffer(final UUID uuid) {
final ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
return byteBuffer.flip();
}
public static UUID fromByteBuffer(final ByteBuffer byteBuffer) {
try {
final long mostSigBits = byteBuffer.getLong();
final long leastSigBits = byteBuffer.getLong();
if (byteBuffer.hasRemaining()) {
throw new IllegalArgumentException("unexpected byte array length; was greater than 16");
}
return new UUID(mostSigBits, leastSigBits);
} catch (BufferUnderflowException e) {
throw new IllegalArgumentException("unexpected byte array length; was less than 16");
public static UUID fromBytes(final byte[] bytes) {
return fromByteBuffer(ByteBuffer.wrap(bytes));
}
public static UUID fromByteBuffer(final ByteBuffer byteBuffer) {
try {
final long mostSigBits = byteBuffer.getLong();
final long leastSigBits = byteBuffer.getLong();
if (byteBuffer.hasRemaining()) {
throw new IllegalArgumentException("unexpected byte array length; was greater than 16");
}
return new UUID(mostSigBits, leastSigBits);
} catch (BufferUnderflowException e) {
throw new IllegalArgumentException("unexpected byte array length; was less than 16");
}
}
public static Optional<UUID> fromStringSafe(final String uuidString) {
try {
return Optional.of(UUID.fromString(uuidString));
} catch (final IllegalArgumentException e) {
return Optional.empty();
}
}
}