Only accept backup receipt redemption when account has a backup credential request
This commit is contained in:
parent
093ac6fb16
commit
ec79386306
|
@ -236,6 +236,12 @@ public class BackupAuthManager {
|
|||
.asRuntimeException();
|
||||
}
|
||||
|
||||
if (account.getBackupCredentialRequest(BackupCredentialType.MEDIA).isEmpty()) {
|
||||
throw Status.ABORTED
|
||||
.withDescription("account must have a backup-id commitment")
|
||||
.asRuntimeException();
|
||||
}
|
||||
|
||||
return redeemedReceiptsManager
|
||||
.put(receiptSerial, receiptExpiration.getEpochSecond(), receiptLevel, account.getUuid())
|
||||
.thenCompose(receiptAllowed -> {
|
||||
|
|
|
@ -173,9 +173,13 @@ public class ArchiveController {
|
|||
|
||||
After successful redemption, subsequent requests to /v1/archive/auth will return credentials with the level on
|
||||
the provided receipt until the expiration time on the receipt.
|
||||
|
||||
Accounts must have an existing backup credential request in order to redeem a receipt. This request will fail
|
||||
if the account has not already set a backup credential request via PUT `/v1/archives/backupid`.
|
||||
""")
|
||||
@ApiResponse(responseCode = "204", description = "The receipt was redeemed")
|
||||
@ApiResponse(responseCode = "400", description = "The provided presentation or receipt was invalid")
|
||||
@ApiResponse(responseCode = "409", description = "The target account does not have a backup-id commitment")
|
||||
@ApiResponse(responseCode = "429", description = "Rate limited.")
|
||||
public CompletionStage<Response> redeemReceipt(
|
||||
@Mutable @Auth final AuthenticatedDevice account,
|
||||
|
|
|
@ -55,6 +55,9 @@ service Backups {
|
|||
* After successful redemption, subsequent requests to
|
||||
* GetBackupAuthCredentials will return credentials with the level on the
|
||||
* provided receipt until the expiration time on the receipt.
|
||||
*
|
||||
* errors:
|
||||
* ABORTED: The target account does not have a backup-id commitment
|
||||
*/
|
||||
rpc RedeemReceipt(RedeemReceiptRequest) returns (RedeemReceiptResponse) {}
|
||||
|
||||
|
|
|
@ -348,6 +348,7 @@ public class BackupAuthManagerTest {
|
|||
final BackupAuthManager authManager = create(BackupLevel.FREE);
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getBackupCredentialRequest(BackupCredentialType.MEDIA)).thenReturn(Optional.of(new byte[0]));
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
|
@ -357,6 +358,24 @@ public class BackupAuthManagerTest {
|
|||
verify(accountsManager, times(1)).updateAsync(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void redeemReceiptNoBackupRequest() {
|
||||
final Instant expirationTime = Instant.EPOCH.plus(Duration.ofDays(1));
|
||||
final BackupAuthManager authManager = create(BackupLevel.FREE);
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getBackupCredentialRequest(BackupCredentialType.MEDIA)).thenReturn(Optional.empty());
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(redeemedReceiptsManager.put(any(), eq(expirationTime.getEpochSecond()), eq(201L), eq(aci)))
|
||||
.thenReturn(CompletableFuture.completedFuture(true));
|
||||
assertThatExceptionOfType(StatusRuntimeException.class)
|
||||
.isThrownBy(() ->
|
||||
authManager.redeemReceipt(account, receiptPresentation(201, expirationTime)).join())
|
||||
.extracting(ex -> ex.getStatus().getCode())
|
||||
.isEqualTo(Status.Code.ABORTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mergeRedemptions() throws InvalidInputException, VerificationFailedException {
|
||||
final Instant newExpirationTime = Instant.EPOCH.plus(Duration.ofDays(1));
|
||||
|
@ -365,6 +384,7 @@ public class BackupAuthManagerTest {
|
|||
final BackupAuthManager authManager = create(BackupLevel.FREE);
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getBackupCredentialRequest(BackupCredentialType.MEDIA)).thenReturn(Optional.of(new byte[0]));
|
||||
|
||||
// The account has an existing voucher with a later expiration date
|
||||
when(account.getBackupVoucher()).thenReturn(new Account.BackupVoucher(201, existingExpirationTime));
|
||||
|
@ -429,6 +449,7 @@ public class BackupAuthManagerTest {
|
|||
final BackupAuthManager authManager = create(BackupLevel.FREE);
|
||||
final Account account = mock(Account.class);
|
||||
when(account.getUuid()).thenReturn(aci);
|
||||
when(account.getBackupCredentialRequest(BackupCredentialType.MEDIA)).thenReturn(Optional.of(new byte[0]));
|
||||
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(1)));
|
||||
when(accountsManager.updateAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(account));
|
||||
|
|
Loading…
Reference in New Issue