Add zkproof validation in username flow
This commit is contained in:
parent
e19c04377b
commit
4fc3949367
2
pom.xml
2
pom.xml
|
@ -296,7 +296,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.signal</groupId>
|
<groupId>org.signal</groupId>
|
||||||
<artifactId>libsignal-server</artifactId>
|
<artifactId>libsignal-server</artifactId>
|
||||||
<version>0.21.1</version>
|
<version>0.22.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
|
|
@ -213,6 +213,7 @@ import org.whispersystems.textsecuregcm.subscriptions.StripeManager;
|
||||||
import org.whispersystems.textsecuregcm.util.Constants;
|
import org.whispersystems.textsecuregcm.util.Constants;
|
||||||
import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig;
|
import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig;
|
||||||
import org.whispersystems.textsecuregcm.util.HostnameUtil;
|
import org.whispersystems.textsecuregcm.util.HostnameUtil;
|
||||||
|
import org.whispersystems.textsecuregcm.util.UsernameHashZkProofVerifier;
|
||||||
import org.whispersystems.textsecuregcm.util.logging.LoggingUnhandledExceptionMapper;
|
import org.whispersystems.textsecuregcm.util.logging.LoggingUnhandledExceptionMapper;
|
||||||
import org.whispersystems.textsecuregcm.util.logging.UncaughtExceptionHandler;
|
import org.whispersystems.textsecuregcm.util.logging.UncaughtExceptionHandler;
|
||||||
import org.whispersystems.textsecuregcm.websocket.AuthenticatedConnectListener;
|
import org.whispersystems.textsecuregcm.websocket.AuthenticatedConnectListener;
|
||||||
|
@ -475,6 +476,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
|
|
||||||
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager);
|
ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager);
|
||||||
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = new RegistrationRecoveryPasswordsManager(registrationRecoveryPasswords);
|
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = new RegistrationRecoveryPasswordsManager(registrationRecoveryPasswords);
|
||||||
|
UsernameHashZkProofVerifier usernameHashZkProofVerifier = new UsernameHashZkProofVerifier();
|
||||||
|
|
||||||
RegistrationServiceClient registrationServiceClient = new RegistrationServiceClient(config.getRegistrationServiceConfiguration().getHost(), config.getRegistrationServiceConfiguration().getPort(), config.getRegistrationServiceConfiguration().getApiKey(), config.getRegistrationServiceConfiguration().getRegistrationCaCertificate(), registrationCallbackExecutor);
|
RegistrationServiceClient registrationServiceClient = new RegistrationServiceClient(config.getRegistrationServiceConfiguration().getHost(), config.getRegistrationServiceConfiguration().getPort(), config.getRegistrationServiceConfiguration().getApiKey(), config.getRegistrationServiceConfiguration().getRegistrationCaCertificate(), registrationCallbackExecutor);
|
||||||
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor, config.getSecureBackupServiceConfiguration());
|
SecureBackupClient secureBackupClient = new SecureBackupClient(backupCredentialsGenerator, backupServiceExecutor, config.getSecureBackupServiceConfiguration());
|
||||||
|
@ -679,7 +681,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
||||||
new AccountController(pendingAccountsManager, accountsManager, rateLimiters,
|
new AccountController(pendingAccountsManager, accountsManager, rateLimiters,
|
||||||
registrationServiceClient, dynamicConfigurationManager, turnTokenGenerator, config.getTestDevices(),
|
registrationServiceClient, dynamicConfigurationManager, turnTokenGenerator, config.getTestDevices(),
|
||||||
captchaChecker, pushNotificationManager, changeNumberManager, registrationLockVerificationManager,
|
captchaChecker, pushNotificationManager, changeNumberManager, registrationLockVerificationManager,
|
||||||
registrationRecoveryPasswordsManager, clock));
|
registrationRecoveryPasswordsManager, usernameHashZkProofVerifier, clock));
|
||||||
|
|
||||||
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
|
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.signal.libsignal.usernames.BaseUsernameException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
|
@ -107,6 +108,7 @@ import org.whispersystems.textsecuregcm.util.HeaderUtils;
|
||||||
import org.whispersystems.textsecuregcm.util.ImpossiblePhoneNumberException;
|
import org.whispersystems.textsecuregcm.util.ImpossiblePhoneNumberException;
|
||||||
import org.whispersystems.textsecuregcm.util.NonNormalizedPhoneNumberException;
|
import org.whispersystems.textsecuregcm.util.NonNormalizedPhoneNumberException;
|
||||||
import org.whispersystems.textsecuregcm.util.Optionals;
|
import org.whispersystems.textsecuregcm.util.Optionals;
|
||||||
|
import org.whispersystems.textsecuregcm.util.UsernameHashZkProofVerifier;
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
|
|
||||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||||
|
@ -160,6 +162,7 @@ public class AccountController {
|
||||||
private final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager;
|
private final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager;
|
||||||
private final ChangeNumberManager changeNumberManager;
|
private final ChangeNumberManager changeNumberManager;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
private final UsernameHashZkProofVerifier usernameHashZkProofVerifier;
|
||||||
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@ -178,6 +181,7 @@ public class AccountController {
|
||||||
ChangeNumberManager changeNumberManager,
|
ChangeNumberManager changeNumberManager,
|
||||||
RegistrationLockVerificationManager registrationLockVerificationManager,
|
RegistrationLockVerificationManager registrationLockVerificationManager,
|
||||||
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager,
|
RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager,
|
||||||
|
UsernameHashZkProofVerifier usernameHashZkProofVerifier,
|
||||||
Clock clock
|
Clock clock
|
||||||
) {
|
) {
|
||||||
this.pendingAccounts = pendingAccounts;
|
this.pendingAccounts = pendingAccounts;
|
||||||
|
@ -192,6 +196,7 @@ public class AccountController {
|
||||||
this.registrationLockVerificationManager = registrationLockVerificationManager;
|
this.registrationLockVerificationManager = registrationLockVerificationManager;
|
||||||
this.changeNumberManager = changeNumberManager;
|
this.changeNumberManager = changeNumberManager;
|
||||||
this.registrationRecoveryPasswordsManager = registrationRecoveryPasswordsManager;
|
this.registrationRecoveryPasswordsManager = registrationRecoveryPasswordsManager;
|
||||||
|
this.usernameHashZkProofVerifier = usernameHashZkProofVerifier;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,6 +717,12 @@ public class AccountController {
|
||||||
@NotNull @Valid ConfirmUsernameHashRequest confirmRequest) throws RateLimitExceededException {
|
@NotNull @Valid ConfirmUsernameHashRequest confirmRequest) throws RateLimitExceededException {
|
||||||
rateLimiters.getUsernameSetLimiter().validate(auth.getAccount().getUuid());
|
rateLimiters.getUsernameSetLimiter().validate(auth.getAccount().getUuid());
|
||||||
|
|
||||||
|
try {
|
||||||
|
usernameHashZkProofVerifier.verifyProof(confirmRequest.zkProof(), confirmRequest.usernameHash());
|
||||||
|
} catch (final BaseUsernameException e) {
|
||||||
|
throw new WebApplicationException(Response.status(422).build());
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Account account = accounts.confirmReservedUsernameHash(auth.getAccount(), confirmRequest.usernameHash());
|
final Account account = accounts.confirmReservedUsernameHash(auth.getAccount(), confirmRequest.usernameHash());
|
||||||
return account
|
return account
|
||||||
|
|
|
@ -15,5 +15,9 @@ public record ConfirmUsernameHashRequest(
|
||||||
@JsonSerialize(using = ByteArrayBase64UrlAdapter.Serializing.class)
|
@JsonSerialize(using = ByteArrayBase64UrlAdapter.Serializing.class)
|
||||||
@JsonDeserialize(using = ByteArrayBase64UrlAdapter.Deserializing.class)
|
@JsonDeserialize(using = ByteArrayBase64UrlAdapter.Deserializing.class)
|
||||||
@ExactlySize(AccountController.USERNAME_HASH_LENGTH)
|
@ExactlySize(AccountController.USERNAME_HASH_LENGTH)
|
||||||
byte[] usernameHash
|
byte[] usernameHash,
|
||||||
|
|
||||||
|
@JsonSerialize(using = ByteArrayBase64UrlAdapter.Serializing.class)
|
||||||
|
@JsonDeserialize(using = ByteArrayBase64UrlAdapter.Deserializing.class)
|
||||||
|
byte[] zkProof
|
||||||
) {}
|
) {}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.whispersystems.textsecuregcm.util;
|
||||||
|
|
||||||
|
import org.signal.libsignal.usernames.BaseUsernameException;
|
||||||
|
import org.signal.libsignal.usernames.Username;
|
||||||
|
|
||||||
|
public class UsernameHashZkProofVerifier {
|
||||||
|
public void verifyProof(byte[] proof, byte[] hash) throws BaseUsernameException {
|
||||||
|
Username.verifyProof(proof, hash);
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,6 +64,7 @@ import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.signal.libsignal.usernames.BaseUsernameException;
|
||||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||||
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialsGenerator;
|
||||||
|
@ -119,6 +120,7 @@ import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.MockUtils;
|
import org.whispersystems.textsecuregcm.util.MockUtils;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
import org.whispersystems.textsecuregcm.util.UsernameHashZkProofVerifier;
|
||||||
|
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class AccountControllerTest {
|
class AccountControllerTest {
|
||||||
|
@ -142,7 +144,8 @@ class AccountControllerTest {
|
||||||
private static final byte[] USERNAME_HASH_2 = Base64.getUrlDecoder().decode(BASE_64_URL_USERNAME_HASH_2);
|
private static final byte[] USERNAME_HASH_2 = Base64.getUrlDecoder().decode(BASE_64_URL_USERNAME_HASH_2);
|
||||||
private static final byte[] INVALID_USERNAME_HASH = Base64.getDecoder().decode(INVALID_BASE_64_URL_USERNAME_HASH);
|
private static final byte[] INVALID_USERNAME_HASH = Base64.getDecoder().decode(INVALID_BASE_64_URL_USERNAME_HASH);
|
||||||
private static final byte[] TOO_SHORT_USERNAME_HASH = Base64.getUrlDecoder().decode(TOO_SHORT_BASE_64_URL_USERNAME_HASH);
|
private static final byte[] TOO_SHORT_USERNAME_HASH = Base64.getUrlDecoder().decode(TOO_SHORT_BASE_64_URL_USERNAME_HASH);
|
||||||
|
private static final String BASE_64_URL_ZK_PROOF = "2kambOgmdeeIO0faCMgR6HR4G2BQ5bnhXdIe9ZuZY0NmQXSra5BzDBQ7jzy1cvoEqUHYLpBYMrXudkYPJaWoQg";
|
||||||
|
private static final byte[] ZK_PROOF = Base64.getUrlDecoder().decode(BASE_64_URL_ZK_PROOF);
|
||||||
private static final UUID SENDER_REG_LOCK_UUID = UUID.randomUUID();
|
private static final UUID SENDER_REG_LOCK_UUID = UUID.randomUUID();
|
||||||
private static final UUID SENDER_TRANSFER_UUID = UUID.randomUUID();
|
private static final UUID SENDER_TRANSFER_UUID = UUID.randomUUID();
|
||||||
|
|
||||||
|
@ -179,10 +182,10 @@ class AccountControllerTest {
|
||||||
private static RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = mock(
|
private static RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager = mock(
|
||||||
RegistrationRecoveryPasswordsManager.class);
|
RegistrationRecoveryPasswordsManager.class);
|
||||||
private static ClientPresenceManager clientPresenceManager = mock(ClientPresenceManager.class);
|
private static ClientPresenceManager clientPresenceManager = mock(ClientPresenceManager.class);
|
||||||
|
private static final UsernameHashZkProofVerifier usernameZkProofVerifier = mock(UsernameHashZkProofVerifier.class);
|
||||||
private static TestClock testClock = TestClock.now();
|
private static TestClock testClock = TestClock.now();
|
||||||
|
|
||||||
private static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
private static DynamicConfigurationManager dynamicConfigurationManager = mock(DynamicConfigurationManager.class);
|
||||||
|
|
||||||
private byte[] registration_lock_key = new byte[32];
|
private byte[] registration_lock_key = new byte[32];
|
||||||
|
|
||||||
private static final SecureBackupServiceConfiguration BACKUP_CFG = MockUtils.buildMock(
|
private static final SecureBackupServiceConfiguration BACKUP_CFG = MockUtils.buildMock(
|
||||||
|
@ -220,6 +223,7 @@ class AccountControllerTest {
|
||||||
changeNumberManager,
|
changeNumberManager,
|
||||||
registrationLockVerificationManager,
|
registrationLockVerificationManager,
|
||||||
registrationRecoveryPasswordsManager,
|
registrationRecoveryPasswordsManager,
|
||||||
|
usernameZkProofVerifier,
|
||||||
testClock))
|
testClock))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -356,7 +360,8 @@ class AccountControllerTest {
|
||||||
captchaChecker,
|
captchaChecker,
|
||||||
pushNotificationManager,
|
pushNotificationManager,
|
||||||
changeNumberManager,
|
changeNumberManager,
|
||||||
clientPresenceManager);
|
clientPresenceManager,
|
||||||
|
usernameZkProofVerifier);
|
||||||
|
|
||||||
clearInvocations(AuthHelper.DISABLED_DEVICE);
|
clearInvocations(AuthHelper.DISABLED_DEVICE);
|
||||||
}
|
}
|
||||||
|
@ -1751,7 +1756,8 @@ class AccountControllerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCommitUsername() throws UsernameHashNotAvailableException, UsernameReservationNotFoundException {
|
void testConfirmUsernameHash()
|
||||||
|
throws UsernameHashNotAvailableException, UsernameReservationNotFoundException, BaseUsernameException {
|
||||||
Account account = mock(Account.class);
|
Account account = mock(Account.class);
|
||||||
when(account.getUsernameHash()).thenReturn(Optional.of(USERNAME_HASH_1));
|
when(account.getUsernameHash()).thenReturn(Optional.of(USERNAME_HASH_1));
|
||||||
when(accountsManager.confirmReservedUsernameHash(any(), eq(USERNAME_HASH_1))).thenReturn(account);
|
when(accountsManager.confirmReservedUsernameHash(any(), eq(USERNAME_HASH_1))).thenReturn(account);
|
||||||
|
@ -1760,13 +1766,15 @@ class AccountControllerTest {
|
||||||
.target("/v1/accounts/username_hash/confirm")
|
.target("/v1/accounts/username_hash/confirm")
|
||||||
.request()
|
.request()
|
||||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1)));
|
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1, ZK_PROOF)));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
assertArrayEquals(response.readEntity(UsernameHashResponse.class).usernameHash(), USERNAME_HASH_1);
|
assertArrayEquals(response.readEntity(UsernameHashResponse.class).usernameHash(), USERNAME_HASH_1);
|
||||||
|
verify(usernameZkProofVerifier).verifyProof(ZK_PROOF, USERNAME_HASH_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCommitUnreservedUsername() throws UsernameHashNotAvailableException, UsernameReservationNotFoundException {
|
void testConfirmUnreservedUsernameHash()
|
||||||
|
throws UsernameHashNotAvailableException, UsernameReservationNotFoundException, BaseUsernameException {
|
||||||
when(accountsManager.confirmReservedUsernameHash(any(), eq(USERNAME_HASH_1)))
|
when(accountsManager.confirmReservedUsernameHash(any(), eq(USERNAME_HASH_1)))
|
||||||
.thenThrow(new UsernameReservationNotFoundException());
|
.thenThrow(new UsernameReservationNotFoundException());
|
||||||
Response response =
|
Response response =
|
||||||
|
@ -1774,12 +1782,14 @@ class AccountControllerTest {
|
||||||
.target("/v1/accounts/username_hash/confirm")
|
.target("/v1/accounts/username_hash/confirm")
|
||||||
.request()
|
.request()
|
||||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1)));
|
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1, ZK_PROOF)));
|
||||||
assertThat(response.getStatus()).isEqualTo(409);
|
assertThat(response.getStatus()).isEqualTo(409);
|
||||||
|
verify(usernameZkProofVerifier).verifyProof(ZK_PROOF, USERNAME_HASH_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCommitLapsedUsername() throws UsernameHashNotAvailableException, UsernameReservationNotFoundException {
|
void testConfirmLapsedUsernameHash()
|
||||||
|
throws UsernameHashNotAvailableException, UsernameReservationNotFoundException, BaseUsernameException {
|
||||||
when(accountsManager.confirmReservedUsernameHash(any(), eq(USERNAME_HASH_1)))
|
when(accountsManager.confirmReservedUsernameHash(any(), eq(USERNAME_HASH_1)))
|
||||||
.thenThrow(new UsernameHashNotAvailableException());
|
.thenThrow(new UsernameHashNotAvailableException());
|
||||||
Response response =
|
Response response =
|
||||||
|
@ -1787,8 +1797,54 @@ class AccountControllerTest {
|
||||||
.target("/v1/accounts/username_hash/confirm")
|
.target("/v1/accounts/username_hash/confirm")
|
||||||
.request()
|
.request()
|
||||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1)));
|
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1, ZK_PROOF)));
|
||||||
assertThat(response.getStatus()).isEqualTo(410);
|
assertThat(response.getStatus()).isEqualTo(410);
|
||||||
|
verify(usernameZkProofVerifier).verifyProof(ZK_PROOF, USERNAME_HASH_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConfirmUsernameHashInvalidBase64UrlEncoding() {
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/accounts/username_hash/confirm")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
|
.put(Entity.json(
|
||||||
|
// Has '+' and '='characters which are invalid in base64url
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"usernameHash": "jh1jJ50oGn9wUXAFNtDus6AJgWOQ6XbZzF+wCv7OOQs=",
|
||||||
|
"zkProof": "iYXE0QPK60PS3lGa-xdNv0GlXA3B03xQLzltSf-2xmscyS_8fjy5H9ymfaEr62PcVY7tsWhWjOOvcCnhmP_HS="
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(422);
|
||||||
|
verifyNoInteractions(usernameZkProofVerifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConfirmUsernameHashInvalidHashSize() {
|
||||||
|
byte[] usernameHash = new byte[31];
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/accounts/username_hash/confirm")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
|
.put(Entity.json(new ConfirmUsernameHashRequest(usernameHash, ZK_PROOF)));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(422);
|
||||||
|
verifyNoInteractions(usernameZkProofVerifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCommitUsernameHashWithInvalidProof() throws BaseUsernameException {
|
||||||
|
doThrow(new BaseUsernameException("invalid username")).when(usernameZkProofVerifier).verifyProof(eq(ZK_PROOF), eq(USERNAME_HASH_1));
|
||||||
|
Response response =
|
||||||
|
resources.getJerseyTest()
|
||||||
|
.target("/v1/accounts/username_hash/confirm")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||||
|
.put(Entity.json(new ConfirmUsernameHashRequest(USERNAME_HASH_1, ZK_PROOF)));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(422);
|
||||||
|
verify(usernameZkProofVerifier).verifyProof(ZK_PROOF, USERNAME_HASH_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue