public Optional<Long> validateAndGetTimestamp(final ExternalServiceCredentials credentials) {
    final String[] parts = requireNonNull(credentials).password().split(DELIMITER);
    final String timestampSeconds;
    final String actualSignature;

    // making sure password format matches our expectations based on the generator configuration
    if (parts.length == 3 && prependUsername) {
      final String username = usernameIsTimestamp() ? parts[0] + DELIMITER + parts[1] : parts[0];
      // username has to match the one from `credentials`
      if (!credentials.username().equals(username)) {
        return Optional.empty();
      }
      timestampSeconds = parts[1];
      actualSignature = parts[2];
    } else if (parts.length == 2 && !prependUsername) {
      timestampSeconds = parts[0];
      actualSignature = parts[1];
    } else {
      // unexpected password format
      return Optional.empty();
    }

    final String signedData = usernameIsTimestamp() ? credentials.username() : credentials.username() + DELIMITER + timestampSeconds;
    final String expectedSignature = truncateSignature
        ? hmac256TruncatedToHexString(key, signedData, TRUNCATED_SIGNATURE_LENGTH)
        : hmac256ToHexString(key, signedData);

    // if the signature is valid it's safe to parse the `timestampSeconds` string into Long
    return hmacHexStringsEqual(expectedSignature, actualSignature)
        ? Optional.of(Long.valueOf(timestampSeconds))
        : Optional.empty();
  }
@Test
  public void testValidateInvalid() throws Exception {
    final ExternalServiceCredentials corruptedStandardUsername = new ExternalServiceCredentials(
        standardCredentials.username(), standardCredentials.password().replace(E164, E164 + "0"));
    final ExternalServiceCredentials corruptedStandardTimestamp = new ExternalServiceCredentials(
        standardCredentials.username(), standardCredentials.password().replace(TIME_SECONDS_STRING, TIME_SECONDS_STRING + "0"));
    final ExternalServiceCredentials corruptedStandardPassword = new ExternalServiceCredentials(
        standardCredentials.username(), standardCredentials.password() + "0");

    final ExternalServiceCredentials corruptedUsernameTimestamp = new ExternalServiceCredentials(
        usernameIsTimestampCredentials.username(), usernameIsTimestampCredentials.password().replace(USERNAME_TIMESTAMP, USERNAME_TIMESTAMP
        + "0"));
    final ExternalServiceCredentials corruptedUsernameTimestampPassword = new ExternalServiceCredentials(
        usernameIsTimestampCredentials.username(), usernameIsTimestampCredentials.password() + "0");

    assertTrue(standardGenerator.validateAndGetTimestamp(corruptedStandardUsername).isEmpty());
    assertTrue(standardGenerator.validateAndGetTimestamp(corruptedStandardTimestamp).isEmpty());
    assertTrue(standardGenerator.validateAndGetTimestamp(corruptedStandardPassword).isEmpty());

    assertTrue(usernameIsTimestampGenerator.validateAndGetTimestamp(corruptedUsernameTimestamp).isEmpty());
    assertTrue(usernameIsTimestampGenerator.validateAndGetTimestamp(corruptedUsernameTimestampPassword).isEmpty());
  }