Validate that sourceAttachments are valid base64 strings
This commit is contained in:
parent
7e353f8ea0
commit
b5f9564e13
|
@ -65,6 +65,7 @@ import org.whispersystems.textsecuregcm.util.ByteArrayBase64UrlAdapter;
|
|||
import org.whispersystems.textsecuregcm.util.ECPublicKeyAdapter;
|
||||
import org.whispersystems.textsecuregcm.util.ExactlySize;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
import org.whispersystems.textsecuregcm.util.ValidBase64URLString;
|
||||
import org.whispersystems.websocket.auth.Mutable;
|
||||
import org.whispersystems.websocket.auth.ReadOnly;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -464,13 +465,16 @@ public class ArchiveController {
|
|||
@Schema(description = "The attachment cdn")
|
||||
@NotNull
|
||||
Integer cdn,
|
||||
|
||||
@NotBlank
|
||||
@ValidBase64URLString
|
||||
@Schema(description = "The attachment key")
|
||||
String key) {}
|
||||
|
||||
public record CopyMediaRequest(
|
||||
@Schema(description = "The object on the attachment CDN to copy")
|
||||
@NotNull
|
||||
@Valid
|
||||
RemoteAttachment sourceAttachment,
|
||||
|
||||
@Schema(description = "The length of the source attachment before the encryption applied by the copy operation")
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.util;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Base64;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Constraint annotation that requires annotated entity is a valid url-base64 encoded string.
|
||||
*/
|
||||
@Target({ FIELD, PARAMETER, METHOD })
|
||||
@Retention(RUNTIME)
|
||||
@Constraint(validatedBy = ValidBase64URLString.Validator.class)
|
||||
@Documented
|
||||
public @interface ValidBase64URLString {
|
||||
|
||||
String message() default "value is not a valid base64 string";
|
||||
|
||||
Class<?>[] groups() default { };
|
||||
|
||||
Class<? extends Payload>[] payload() default { };
|
||||
|
||||
class Validator implements ConstraintValidator<ValidBase64URLString, String> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(final String value, final ConstraintValidatorContext context) {
|
||||
if (Objects.isNull(value)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Base64.getUrlDecoder().decode(value);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -594,6 +594,27 @@ public class ArchiveControllerTest {
|
|||
assertThat(response.getStatus()).isEqualTo(204);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidSourceAttachmentKey() throws VerificationFailedException {
|
||||
final BackupAuthCredentialPresentation presentation = backupAuthTestUtil.getPresentation(
|
||||
BackupLevel.MEDIA, backupKey, aci);
|
||||
when(backupManager.authenticateBackupUser(any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(backupUser(presentation.getBackupId(), BackupLevel.MEDIA)));
|
||||
final Response r = resources.getJerseyTest()
|
||||
.target("v1/archives/media")
|
||||
.request()
|
||||
.header("X-Signal-ZK-Auth", Base64.getEncoder().encodeToString(presentation.serialize()))
|
||||
.header("X-Signal-ZK-Auth-Signature", "aaa")
|
||||
.put(Entity.json(new ArchiveController.CopyMediaRequest(
|
||||
new ArchiveController.RemoteAttachment(3, "invalid/urlBase64"),
|
||||
100,
|
||||
TestRandomUtil.nextBytes(15),
|
||||
TestRandomUtil.nextBytes(32),
|
||||
TestRandomUtil.nextBytes(32),
|
||||
TestRandomUtil.nextBytes(16))));
|
||||
assertThat(r.getStatus()).isEqualTo(422);
|
||||
}
|
||||
|
||||
private static AuthenticatedBackupUser backupUser(byte[] backupId, BackupLevel backupLevel) {
|
||||
return new AuthenticatedBackupUser(backupId, backupLevel, "myBackupDir", "myMediaDir");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue