mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-22 16:48:04 +01:00
Make Backup methods synchronous
This commit is contained in:
@@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
@@ -64,7 +65,6 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
||||
import org.whispersystems.textsecuregcm.tests.util.ExperimentHelper;
|
||||
import org.whispersystems.textsecuregcm.util.CompletableFutureTestUtil;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
import org.whispersystems.textsecuregcm.util.TestRandomUtil;
|
||||
|
||||
@@ -107,19 +107,18 @@ public class BackupAuthManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void commitBackupId() {
|
||||
void commitBackupId() throws RateLimitExceededException {
|
||||
final BackupAuthManager authManager = create();
|
||||
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(accountsManager.updateAsync(any(), any()))
|
||||
when(accountsManager.update(any(), any()))
|
||||
.thenAnswer(invocation -> {
|
||||
final Account a = invocation.getArgument(0);
|
||||
final Consumer<Account> updater = invocation.getArgument(1);
|
||||
|
||||
updater.accept(a);
|
||||
|
||||
return CompletableFuture.completedFuture(a);
|
||||
return a;
|
||||
});
|
||||
|
||||
final BackupAuthCredentialRequest messagesCredentialRequest = backupAuthTestUtil.getRequest(messagesBackupKey, aci);
|
||||
@@ -127,7 +126,7 @@ public class BackupAuthManagerTest {
|
||||
|
||||
authManager.commitBackupId(account, primaryDevice(),
|
||||
Optional.of(messagesCredentialRequest),
|
||||
Optional.of(mediaCredentialRequest)).join();
|
||||
Optional.of(mediaCredentialRequest));
|
||||
|
||||
verify(account).setBackupCredentialRequests(messagesCredentialRequest.serialize(),
|
||||
mediaCredentialRequest.serialize());
|
||||
@@ -138,13 +137,13 @@ public class BackupAuthManagerTest {
|
||||
void commitOnAnyBackupLevel(final BackupLevel backupLevel) {
|
||||
final BackupAuthManager authManager = create();
|
||||
final Account account = new MockAccountBuilder().backupLevel(backupLevel).build();
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
|
||||
final ThrowableAssert.ThrowingCallable commit = () ->
|
||||
authManager.commitBackupId(account,
|
||||
primaryDevice(),
|
||||
Optional.of(backupAuthTestUtil.getRequest(messagesBackupKey, aci)),
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci))).join();
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci)));
|
||||
Assertions.assertThatNoException().isThrownBy(commit);
|
||||
}
|
||||
|
||||
@@ -152,13 +151,13 @@ public class BackupAuthManagerTest {
|
||||
void commitRequiresPrimary() {
|
||||
final BackupAuthManager authManager = create();
|
||||
final Account account = new MockAccountBuilder().build();
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
|
||||
final ThrowableAssert.ThrowingCallable commit = () ->
|
||||
authManager.commitBackupId(account,
|
||||
linkedDevice(),
|
||||
Optional.of(backupAuthTestUtil.getRequest(messagesBackupKey, aci)),
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci))).join();
|
||||
Optional.of(backupAuthTestUtil.getRequest(mediaBackupKey, aci)));
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(commit)
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
@@ -186,7 +185,7 @@ public class BackupAuthManagerTest {
|
||||
|
||||
final RedemptionRange range = range(Duration.ofDays(1));
|
||||
final List<BackupAuthManager.Credential> creds =
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))).join();
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1)));
|
||||
|
||||
assertThat(creds).hasSize(2);
|
||||
assertThat(requestContext
|
||||
@@ -207,7 +206,7 @@ public class BackupAuthManagerTest {
|
||||
.mediaCredential(backupAuthTestUtil.getRequest(mediaBackupKey, aci))
|
||||
.build();
|
||||
|
||||
assertThat(authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))).join())
|
||||
assertThat(authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))))
|
||||
.hasSize(2);
|
||||
}
|
||||
|
||||
@@ -220,7 +219,7 @@ public class BackupAuthManagerTest {
|
||||
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))).join())
|
||||
authManager.getBackupAuthCredentials(account, credentialType, range(Duration.ofDays(1))))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.NOT_FOUND);
|
||||
}
|
||||
@@ -245,7 +244,7 @@ public class BackupAuthManagerTest {
|
||||
.build();
|
||||
|
||||
final List<BackupAuthManager.Credential> creds = authManager.getBackupAuthCredentials(account,
|
||||
credentialType, range(Duration.ofDays(7))).join();
|
||||
credentialType, range(Duration.ofDays(7)));
|
||||
|
||||
assertThat(creds).hasSize(8);
|
||||
Instant redemptionTime = clock.instant().truncatedTo(ChronoUnit.DAYS);
|
||||
@@ -275,7 +274,7 @@ public class BackupAuthManagerTest {
|
||||
final List<BackupAuthManager.Credential> creds = authManager.getBackupAuthCredentials(
|
||||
account,
|
||||
BackupCredentialType.MESSAGES,
|
||||
range(RedemptionRange.MAX_REDEMPTION_DURATION)).join();
|
||||
range(RedemptionRange.MAX_REDEMPTION_DURATION));
|
||||
Instant redemptionTime = Instant.EPOCH;
|
||||
final BackupAuthCredentialRequestContext requestContext = BackupAuthCredentialRequestContext.create(
|
||||
messagesBackupKey, aci);
|
||||
@@ -311,15 +310,15 @@ public class BackupAuthManagerTest {
|
||||
.backupVoucher(null)
|
||||
.build();
|
||||
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(updated));
|
||||
when(accountsManager.update(any(), any())).thenReturn(updated);
|
||||
|
||||
clock.pin(day2.plus(Duration.ofSeconds(1)));
|
||||
assertThat(authManager.getBackupAuthCredentials(account, BackupCredentialType.MESSAGES, range(Duration.ofDays(7))).join())
|
||||
assertThat(authManager.getBackupAuthCredentials(account, BackupCredentialType.MESSAGES, range(Duration.ofDays(7))))
|
||||
.hasSize(8);
|
||||
|
||||
@SuppressWarnings("unchecked") final ArgumentCaptor<Consumer<Account>> accountUpdater = ArgumentCaptor.forClass(
|
||||
Consumer.class);
|
||||
verify(accountsManager, times(1)).updateAsync(any(), accountUpdater.capture());
|
||||
verify(accountsManager, times(1)).update(any(), accountUpdater.capture());
|
||||
|
||||
// If the account is not expired when we go to update it, we shouldn't wipe it out
|
||||
final Account alreadyUpdated = mock(Account.class);
|
||||
@@ -343,11 +342,11 @@ public class BackupAuthManagerTest {
|
||||
.mediaCredential(Optional.of(new byte[0]))
|
||||
.build();
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
when(redeemedReceiptsManager.put(any(), eq(expirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)).join();
|
||||
verify(accountsManager, times(1)).updateAsync(any(), any());
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime));
|
||||
verify(accountsManager, times(1)).update(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -361,7 +360,7 @@ public class BackupAuthManagerTest {
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)).join())
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.ABORTED);
|
||||
}
|
||||
@@ -379,13 +378,13 @@ public class BackupAuthManagerTest {
|
||||
.build();
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
when(redeemedReceiptsManager.put(any(), eq(newExpirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, newExpirationTime)).join();
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, newExpirationTime));
|
||||
|
||||
final ArgumentCaptor<Consumer<Account>> updaterCaptor = ArgumentCaptor.captor();
|
||||
verify(accountsManager, times(1)).updateAsync(any(), updaterCaptor.capture());
|
||||
verify(accountsManager, times(1)).update(any(), updaterCaptor.capture());
|
||||
|
||||
updaterCaptor.getValue().accept(account);
|
||||
// Should select the voucher with the later expiration time
|
||||
@@ -398,7 +397,7 @@ public class BackupAuthManagerTest {
|
||||
clock.pin(expirationTime.plus(Duration.ofSeconds(1)));
|
||||
final BackupAuthManager authManager = create();
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), receiptPresentation(3, expirationTime)).join())
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), receiptPresentation(3, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -413,7 +412,7 @@ public class BackupAuthManagerTest {
|
||||
final BackupAuthManager authManager = create();
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.redeemReceipt(mock(Account.class), receiptPresentation(level, expirationTime)).join())
|
||||
authManager.redeemReceipt(mock(Account.class), receiptPresentation(level, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -425,7 +424,7 @@ public class BackupAuthManagerTest {
|
||||
final BackupAuthManager authManager = create();
|
||||
final ReceiptCredentialPresentation invalid = receiptPresentation(ServerSecretParams.generate(), 3L, Instant.EPOCH);
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), invalid).join())
|
||||
.isThrownBy(() -> authManager.redeemReceipt(mock(Account.class), invalid))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -433,7 +432,7 @@ public class BackupAuthManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void receiptAlreadyRedeemed() throws InvalidInputException, VerificationFailedException {
|
||||
void receiptAlreadyRedeemed() {
|
||||
final Instant expirationTime = Instant.EPOCH.plus(Duration.ofDays(1));
|
||||
final BackupAuthManager authManager = create();
|
||||
final Account account = new MockAccountBuilder()
|
||||
@@ -441,12 +440,12 @@ public class BackupAuthManagerTest {
|
||||
.build();
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
when(redeemedReceiptsManager.put(any(), eq(expirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(false));
|
||||
|
||||
final CompletableFuture<Void> result = authManager.redeemReceipt(account, receiptPresentation(201, expirationTime));
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(StatusRuntimeException.class, result))
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)))
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
verifyNoInteractions(accountsManager);
|
||||
@@ -484,8 +483,7 @@ public class BackupAuthManagerTest {
|
||||
? new Account.BackupVoucher(1, Instant.EPOCH.plus(Duration.ofSeconds(1)))
|
||||
: null)
|
||||
.build();
|
||||
final BackupAuthManager.BackupIdRotationLimit limit = authManager.checkBackupIdRotationLimit(account)
|
||||
.toCompletableFuture().join();
|
||||
final BackupAuthManager.BackupIdRotationLimit limit = authManager.checkBackupIdRotationLimit(account);
|
||||
final boolean expectHasPermits = !messageLimited && (!mediaLimited || !hasVoucher);
|
||||
final Duration expectedDuration = expectHasPermits ? Duration.ZERO : Duration.ofDays(1);
|
||||
assertThat(limit.hasPermitsRemaining()).isEqualTo(expectHasPermits);
|
||||
@@ -524,7 +522,7 @@ public class BackupAuthManagerTest {
|
||||
.backupVoucher(backupVoucher)
|
||||
.build();
|
||||
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
when(accountsManager.update(any(), any())).thenReturn(account);
|
||||
|
||||
final Optional<BackupAuthCredentialRequest> newMessagesCredential = switch (messageChange) {
|
||||
case MATCH -> Optional.of(storedMessagesCredential);
|
||||
@@ -543,7 +541,7 @@ public class BackupAuthManagerTest {
|
||||
final boolean expectRateLimit = ((mediaChange == CredentialChangeType.MISMATCH) && rateLimitMediaBackupId && paid)
|
||||
|| ((messageChange == CredentialChangeType.MISMATCH) && rateLimitMessagesBackupId);
|
||||
final ThrowableAssert.ThrowingCallable commit = () ->
|
||||
authManager.commitBackupId(account, primaryDevice(), newMessagesCredential, newMediaCredential).join();
|
||||
authManager.commitBackupId(account, primaryDevice(), newMessagesCredential, newMediaCredential);
|
||||
|
||||
if (messageChange == CredentialChangeType.NO_UPDATE && mediaChange == CredentialChangeType.NO_UPDATE) {
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
@@ -551,7 +549,7 @@ public class BackupAuthManagerTest {
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.INVALID_ARGUMENT);
|
||||
} else if (expectRateLimit) {
|
||||
assertThatException().isThrownBy(commit).withRootCauseInstanceOf(RateLimitExceededException.class);
|
||||
assertThatExceptionOfType(RateLimitExceededException.class).isThrownBy(commit);
|
||||
} else {
|
||||
assertThatNoException().isThrownBy(commit);
|
||||
}
|
||||
@@ -611,26 +609,29 @@ public class BackupAuthManagerTest {
|
||||
}
|
||||
|
||||
|
||||
private static RateLimiters rateLimiter(final UUID aci, boolean rateLimitBackupId,
|
||||
boolean rateLimitPaidMediaBackupId) {
|
||||
final RateLimiters limiters = mock(RateLimiters.class);
|
||||
private static RateLimiters rateLimiter(final UUID aci, boolean rateLimitBackupId, boolean rateLimitPaidMediaBackupId) {
|
||||
try {
|
||||
final RateLimiters limiters = mock(RateLimiters.class);
|
||||
|
||||
final RateLimiter allowLimiter = mock(RateLimiter.class);
|
||||
when(allowLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(CompletableFuture.completedFuture(true));
|
||||
when(allowLimiter.validateAsync(aci)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(allowLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
final RateLimiter allowLimiter = mock(RateLimiter.class);
|
||||
when(allowLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(
|
||||
CompletableFuture.completedFuture(true));
|
||||
when(allowLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
|
||||
final RateLimiter denyLimiter = mock(RateLimiter.class);
|
||||
when(denyLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(CompletableFuture.completedFuture(false));
|
||||
when(denyLimiter.validateAsync(aci))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RateLimitExceededException(null)));
|
||||
when(denyLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
final RateLimiter denyLimiter = mock(RateLimiter.class);
|
||||
when(denyLimiter.hasAvailablePermitsAsync(eq(aci), anyLong())).thenReturn(
|
||||
CompletableFuture.completedFuture(false));
|
||||
doThrow(new RateLimitExceededException(null)).when(denyLimiter).validate(aci);
|
||||
when(denyLimiter.config()).thenReturn(new RateLimiterConfig(1, Duration.ofDays(1), false));
|
||||
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_BACKUP_ID))
|
||||
.thenReturn(rateLimitBackupId ? denyLimiter : allowLimiter);
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_PAID_MEDIA_BACKUP_ID))
|
||||
.thenReturn(rateLimitPaidMediaBackupId ? denyLimiter : allowLimiter);
|
||||
return limiters;
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_BACKUP_ID))
|
||||
.thenReturn(rateLimitBackupId ? denyLimiter : allowLimiter);
|
||||
when(limiters.forDescriptor(RateLimiters.For.SET_PAID_MEDIA_BACKUP_ID))
|
||||
.thenReturn(rateLimitPaidMediaBackupId ? denyLimiter : allowLimiter);
|
||||
return limiters;
|
||||
} catch (RateLimitExceededException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private RedemptionRange range(Duration length) {
|
||||
|
||||
@@ -76,6 +76,6 @@ public class BackupAuthTestUtil {
|
||||
});
|
||||
final RedemptionRange redemptionRange;
|
||||
redemptionRange = RedemptionRange.inclusive(clock, redemptionStart, redemptionEnd);
|
||||
return issuer.getBackupAuthCredentials(account, credentialType, redemptionRange).join();
|
||||
return issuer.getBackupAuthCredentials(account, credentialType, redemptionRange);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -230,11 +231,11 @@ public class BackupManagerTest {
|
||||
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MESSAGES, backupLevel);
|
||||
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
verify(tusCredentialGenerator, times(1))
|
||||
.generateUpload("%s/%s".formatted(backupUser.backupDir(), BackupManager.MESSAGE_BACKUP_NAME));
|
||||
|
||||
final BackupManager.BackupInfo info = backupManager.backupInfo(backupUser).join();
|
||||
final BackupManager.BackupInfo info = backupManager.backupInfo(backupUser);
|
||||
assertThat(info.backupSubdir()).isEqualTo(backupUser.backupDir()).isNotBlank();
|
||||
assertThat(info.messageBackupKey()).isEqualTo(BackupManager.MESSAGE_BACKUP_NAME);
|
||||
assertThat(info.mediaUsedSpace()).isEqualTo(Optional.empty());
|
||||
@@ -253,18 +254,17 @@ public class BackupManagerTest {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MEDIA, backupLevel);
|
||||
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.createMessageBackupUploadDescriptor(backupUser).join())
|
||||
.isThrownBy(() -> backupManager.createMessageBackupUploadDescriptor(backupUser))
|
||||
.matches(exception -> exception.getStatus().getCode() == Status.UNAUTHENTICATED.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTemporaryMediaAttachmentRateLimited() {
|
||||
public void createTemporaryMediaAttachmentRateLimited() throws RateLimitExceededException {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MEDIA, BackupLevel.PAID);
|
||||
when(mediaUploadLimiter.validateAsync(eq(BackupManager.rateLimitKey(backupUser))))
|
||||
.thenReturn(CompletableFuture.failedFuture(new RateLimitExceededException(null)));
|
||||
CompletableFutureTestUtil.assertFailsWithCause(
|
||||
RateLimitExceededException.class,
|
||||
backupManager.createTemporaryAttachmentUploadDescriptor(backupUser).toCompletableFuture());
|
||||
doThrow(new RateLimitExceededException(null))
|
||||
.when(mediaUploadLimiter).validate(eq(BackupManager.rateLimitKey(backupUser)));
|
||||
assertThatExceptionOfType(RateLimitExceededException.class)
|
||||
.isThrownBy(() -> backupManager.createTemporaryAttachmentUploadDescriptor(backupUser));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -297,11 +297,11 @@ public class BackupManagerTest {
|
||||
|
||||
// create backup at t=tstart
|
||||
testClock.pin(tstart);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
// refresh at t=tnext
|
||||
testClock.pin(tnext);
|
||||
backupManager.ttlRefresh(backupUser).join();
|
||||
backupManager.ttlRefresh(backupUser);
|
||||
|
||||
checkExpectedExpirations(
|
||||
tnext.truncatedTo(ChronoUnit.DAYS),
|
||||
@@ -319,11 +319,11 @@ public class BackupManagerTest {
|
||||
|
||||
// create backup at t=tstart
|
||||
testClock.pin(tstart);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
// create again at t=tnext
|
||||
testClock.pin(tnext);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
checkExpectedExpirations(
|
||||
tnext.truncatedTo(ChronoUnit.DAYS),
|
||||
@@ -363,7 +363,7 @@ public class BackupManagerTest {
|
||||
backupManager.setPublicKey(
|
||||
presentation,
|
||||
keyPair.getPrivateKey().calculateSignature(presentation.serialize()),
|
||||
keyPair.getPublicKey()).join();
|
||||
keyPair.getPublicKey());
|
||||
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.authenticateBackupUser(
|
||||
@@ -384,10 +384,10 @@ public class BackupManagerTest {
|
||||
final byte[] signature = keyPair.getPrivateKey().calculateSignature(presentation.serialize());
|
||||
|
||||
// haven't set a public key yet
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(
|
||||
StatusRuntimeException.class,
|
||||
backupManager.authenticateBackupUser(presentation, signature, null))
|
||||
.getStatus().getCode())
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.authenticateBackupUser(presentation, signature, null))
|
||||
.extracting(StatusRuntimeException::getStatus)
|
||||
.extracting(Status::getCode)
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
}
|
||||
|
||||
@@ -401,17 +401,17 @@ public class BackupManagerTest {
|
||||
final byte[] signature1 = keyPair1.getPrivateKey().calculateSignature(presentation.serialize());
|
||||
final byte[] signature2 = keyPair2.getPrivateKey().calculateSignature(presentation.serialize());
|
||||
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey()).join();
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey());
|
||||
|
||||
// shouldn't be able to set a different public key
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(
|
||||
StatusRuntimeException.class,
|
||||
assertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() ->
|
||||
backupManager.setPublicKey(presentation, signature2, keyPair2.getPublicKey()))
|
||||
.getStatus().getCode())
|
||||
.extracting(StatusRuntimeException::getStatus)
|
||||
.extracting(Status::getCode)
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
|
||||
// should be able to set the same public key again (noop)
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey()).join();
|
||||
backupManager.setPublicKey(presentation, signature1, keyPair1.getPublicKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -432,17 +432,17 @@ public class BackupManagerTest {
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
|
||||
backupManager.setPublicKey(presentation, signature, keyPair.getPublicKey()).join();
|
||||
backupManager.setPublicKey(presentation, signature, keyPair.getPublicKey());
|
||||
|
||||
// shouldn't be able to authenticate with an invalid signature
|
||||
assertThat(CompletableFutureTestUtil.assertFailsWithCause(
|
||||
StatusRuntimeException.class,
|
||||
backupManager.authenticateBackupUser(presentation, wrongSignature, null))
|
||||
.getStatus().getCode())
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() -> backupManager.authenticateBackupUser(presentation, wrongSignature, null))
|
||||
.extracting(StatusRuntimeException::getStatus)
|
||||
.extracting(Status::getCode)
|
||||
.isEqualTo(Status.UNAUTHENTICATED.getCode());
|
||||
|
||||
// correct signature
|
||||
final AuthenticatedBackupUser user = backupManager.authenticateBackupUser(presentation, signature, null).join();
|
||||
final AuthenticatedBackupUser user = backupManager.authenticateBackupUser(presentation, signature, null);
|
||||
assertThat(user.backupId()).isEqualTo(presentation.getBackupId());
|
||||
assertThat(user.backupLevel()).isEqualTo(BackupLevel.FREE);
|
||||
}
|
||||
@@ -456,15 +456,15 @@ public class BackupManagerTest {
|
||||
backupKey, aci);
|
||||
final ECKeyPair keyPair = ECKeyPair.generate();
|
||||
final byte[] signature = keyPair.getPrivateKey().calculateSignature(oldCredential.serialize());
|
||||
backupManager.setPublicKey(oldCredential, signature, keyPair.getPublicKey()).join();
|
||||
backupManager.setPublicKey(oldCredential, signature, keyPair.getPublicKey());
|
||||
|
||||
// should be accepted the day before to forgive clock skew
|
||||
testClock.pin(Instant.ofEpochSecond(1));
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null).join());
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null));
|
||||
|
||||
// should be accepted the day after to forgive clock skew
|
||||
testClock.pin(Instant.ofEpochSecond(1).plus(Duration.ofDays(2)));
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null).join());
|
||||
assertThatNoException().isThrownBy(() -> backupManager.authenticateBackupUser(oldCredential, signature, null));
|
||||
|
||||
// should be rejected the day after that
|
||||
testClock.pin(Instant.ofEpochSecond(1).plus(Duration.ofDays(3)));
|
||||
@@ -713,8 +713,7 @@ public class BackupManagerTest {
|
||||
Optional.of("newCursor")
|
||||
)));
|
||||
|
||||
final BackupManager.ListMediaResult result = backupManager.list(backupUser, cursor, 17)
|
||||
.toCompletableFuture().join();
|
||||
final BackupManager.ListMediaResult result = backupManager.list(backupUser, cursor, 17);
|
||||
assertThat(result.media()).hasSize(1);
|
||||
assertThat(result.media().getFirst().cdn()).isEqualTo(13);
|
||||
assertThat(result.media().getFirst().key()).isEqualTo(
|
||||
@@ -733,7 +732,7 @@ public class BackupManagerTest {
|
||||
when(svrbClient.removeData(anyString())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
||||
// Deleting should swap the backupDir for the user
|
||||
backupManager.deleteEntireBackup(original).join();
|
||||
backupManager.deleteEntireBackup(original);
|
||||
verifyNoInteractions(remoteStorageManager);
|
||||
verify(svrbClient).removeData(HexFormat.of().formatHex(BackupsDb.hashedBackupId(original.backupId())));
|
||||
|
||||
@@ -747,7 +746,7 @@ public class BackupManagerTest {
|
||||
Collections.emptyList(),
|
||||
Optional.empty()
|
||||
)));
|
||||
backupManager.deleteEntireBackup(after).join();
|
||||
backupManager.deleteEntireBackup(after);
|
||||
verify(remoteStorageManager, times(1))
|
||||
.list(eq(after.backupDir() + "/"), eq(Optional.empty()), anyLong());
|
||||
|
||||
@@ -914,7 +913,7 @@ public class BackupManagerTest {
|
||||
.toList();
|
||||
for (int i = 0; i < backupUsers.size(); i++) {
|
||||
testClock.pin(days(i));
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUsers.get(i)).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUsers.get(i));
|
||||
}
|
||||
|
||||
// set of backup-id hashes that should be expired (initially t=0)
|
||||
@@ -949,11 +948,11 @@ public class BackupManagerTest {
|
||||
|
||||
// refreshed media timestamp at t=5
|
||||
testClock.pin(days(5));
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.PAID)).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.PAID));
|
||||
|
||||
// refreshed messages timestamp at t=6
|
||||
testClock.pin(days(6));
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.FREE)).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser(backupId, BackupCredentialType.MESSAGES, BackupLevel.FREE));
|
||||
|
||||
Function<Instant, List<ExpiredBackup>> getExpired = time -> backupManager
|
||||
.getExpiredBackups(1, Schedulers.immediate(), time)
|
||||
@@ -974,7 +973,7 @@ public class BackupManagerTest {
|
||||
@EnumSource(mode = EnumSource.Mode.INCLUDE, names = {"MEDIA", "ALL"})
|
||||
public void expireBackup(ExpiredBackup.ExpirationType expirationType) {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MESSAGES, BackupLevel.PAID);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
final String expectedPrefixToDelete = switch (expirationType) {
|
||||
case ALL -> backupUser.backupDir();
|
||||
@@ -1020,7 +1019,7 @@ public class BackupManagerTest {
|
||||
@Test
|
||||
public void deleteBackupPaginated() {
|
||||
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MESSAGES, BackupLevel.PAID);
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser).join();
|
||||
backupManager.createMessageBackupUploadDescriptor(backupUser);
|
||||
|
||||
final ExpiredBackup expiredBackup = expiredBackup(ExpiredBackup.ExpirationType.MEDIA, backupUser);
|
||||
final String mediaPrefix = expiredBackup.prefixToDelete() + "/";
|
||||
|
||||
Reference in New Issue
Block a user