@Override
  public Mono<SetRegistrationLockResponse> setRegistrationLock(final SetRegistrationLockRequest request) {
    final AuthenticatedDevice authenticatedDevice = AuthenticationUtil.requireAuthenticatedPrimaryDevice();

    if (request.getRegistrationLock().isEmpty()) {
      throw Status.INVALID_ARGUMENT.withDescription("Registration lock secret must not be empty").asRuntimeException();
    }

    return Mono.fromFuture(() -> accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()))
        .map(maybeAccount -> maybeAccount.orElseThrow(Status.UNAUTHENTICATED::asRuntimeException))
        .flatMap(account -> {
          // In the previous REST-based API, clients would send hex strings directly. For backward compatibility, we
          // convert the registration lock secret to a lowercase hex string before turning it into a salted hash.
          final SaltedTokenHash credentials =
              SaltedTokenHash.generateFor(HexFormat.of().withLowerCase().formatHex(request.getRegistrationLock().toByteArray()));

          return Mono.fromFuture(() -> accountsManager.updateAsync(account,
              a -> a.setRegistrationLock(credentials.hash(), credentials.salt())));
        })
        .map(ignored -> SetRegistrationLockResponse.newBuilder().build());
  }
@Test
  void setRegistrationLock() {
    final Account account = mock(Account.class);

    when(accountsManager.getByAccountIdentifierAsync(AUTHENTICATED_ACI))
        .thenReturn(CompletableFuture.completedFuture(Optional.of(account)));

    final byte[] registrationLockSecret = TestRandomUtil.nextBytes(32);

    final SetRegistrationLockResponse ignored =
        authenticatedServiceStub().setRegistrationLock(SetRegistrationLockRequest.newBuilder()
            .setRegistrationLock(ByteString.copyFrom(registrationLockSecret))
            .build());

    final ArgumentCaptor<String> hashCaptor = ArgumentCaptor.forClass(String.class);
    final ArgumentCaptor<String> saltCaptor = ArgumentCaptor.forClass(String.class);

    verify(account).setRegistrationLock(hashCaptor.capture(), saltCaptor.capture());

    final SaltedTokenHash registrationLock = new SaltedTokenHash(hashCaptor.getValue(), saltCaptor.getValue());
    assertTrue(registrationLock.verify(HexFormat.of().formatHex(registrationLockSecret)));
  }