diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java index f8539db45..e03f8278c 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java @@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.backup; import com.google.common.annotations.VisibleForTesting; import io.grpc.Status; import io.micrometer.core.instrument.Metrics; +import java.io.IOException; import java.net.URI; import java.time.Clock; import java.time.Duration; @@ -248,12 +249,17 @@ public class BackupManager { .asRuntimeException(); } + final URI sourceUri; + try { + sourceUri = attachmentReadUri(sourceCdn, sourceKey); + } catch (IOException e) { + return CompletableFuture.failedFuture(e); + } + final MessageBackupUploadDescriptor dst = cdn3BackupCredentialGenerator.generateUpload( cdnMediaPath(backupUser, destinationMediaId)); final int destinationLength = encryptionParameters.outputSize(sourceLength); - - final URI sourceUri = attachmentReadUri(sourceCdn, sourceKey); return this.backupsDb // Write the ddb updates before actually updating backing storage .trackMedia(backupUser, 1, destinationLength) @@ -282,10 +288,10 @@ public class BackupManager { * @param key the attachment key * @return A {@link URI} where the attachment can be retrieved */ - private URI attachmentReadUri(final int cdn, final String key) { + private URI attachmentReadUri(final int cdn, final String key) throws IOException { final String baseUri = attachmentCdnBaseUris.get(cdn); if (baseUri == null) { - throw Status.INVALID_ARGUMENT.withDescription("Unknown cdn " + cdn).asRuntimeException(); + throw new SourceObjectNotFoundException("Unknown attachment cdn " + cdn); } return URI.create("%s/%s".formatted(baseUri, key)); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/backup/SourceObjectNotFoundException.java b/service/src/main/java/org/whispersystems/textsecuregcm/backup/SourceObjectNotFoundException.java index 5d2b20f3b..078a1d13e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/backup/SourceObjectNotFoundException.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/backup/SourceObjectNotFoundException.java @@ -8,4 +8,10 @@ package org.whispersystems.textsecuregcm.backup; import java.io.IOException; public class SourceObjectNotFoundException extends IOException { + public SourceObjectNotFoundException() { + super(); + } + public SourceObjectNotFoundException(String message) { + super(message); + } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupManagerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupManagerTest.java index 4a5540925..8fa04e9eb 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupManagerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupManagerTest.java @@ -39,7 +39,6 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import javax.annotation.Nullable; import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -308,6 +307,17 @@ public class BackupManagerTest { assertThat(AttributeValues.getLong(backup, BackupsDb.ATTR_MEDIA_COUNT, -1L)).isEqualTo(0L); } + @Test + public void unknownSourceCdn() { + final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupTier.MEDIA); + CompletableFutureTestUtil.assertFailsWithCause(SourceObjectNotFoundException.class, + backupManager.copyToBackup( + backupUser, + 0, "abc", 100, + mock(MediaEncryptionParameters.class), + "def".getBytes(StandardCharsets.UTF_8))); + } + @Test public void quotaEnforcementNoRecalculation() { final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupTier.MEDIA);